//info文件例子:
[General]
Name=CN37-MIC
Class=0x260404
SupportedTechnologies=BR/EDR;
Trusted=false
Blocked=false
Services=0000110b-0000-1000-8000-00805f9b34fb;0000110e-0000-1000-8000-00805f9b34fb;0000111e-0000-1000-8000-00805f9b34fb;

[LinkKey]
Key=8FBA1E151BC4AA83AD2F7D091FD1FC5F
Type=4
PINLength=0

//cache/<蓝牙设备地址> 文件内容. 
//ServiceRecords 的内容应该是配对时加入的. 仅扫描时, 只有Name属性.
[General]
Name=CN37-MIC

[ServiceRecords]
0x00000002=353E0900000A00000002090001350619111E191203090004350C3503190100350519000308040900093508350619111E0901080901002502484609031109003F
0x00000003=35440900000A00000003090001350319110B0900043510350619010009001935061900190901030900093508350619110D09010309010025074175642D536E6B
0x00000004=35480900000A00000004090001350619110E19110F0900043510350619010009001735061900170901040900093508350619110E090106090100250841565243

struct main_opts main_opts;
	-> name = BlueZ 5.47 <tag1> <tag2 main.conf:"General", "Name">
	->pairto = DEFAULT_PAIRABLE_TIMEOUT <tag2>
	->discovto = DEFAULT_DISCOVERABLE_TIMEOUT <tag2>
	->reverse_sdp = TRUE;
	->name_resolv = TRUE;
	->debug_keys = FALSE;
	->privacy  <tag3> <set by main.conf: "General", "Privacy">
	->class  <main.conf : "General", "Class">
	->fast_conn <main.conf "General","FastConnectable"> <频繁监听外接设备的请求, 以快速响应, 增加耗电.>

@src/log.c
#define LOG_FILE        "/tmp/bt.log"

main_conf_file_path = CONFIGDIR "/main.conf"
#define CONFIGDIR "/etc/bluetooth"

DBusConnection *dbus_conn <tag4>

struct mgmt *mgmt_master <tag5> <obj2>

static GSList *plugins <list1>
	=>struct bluetooth_plugin *plugin <tag6 加入plugin>

static GList *adapter_list
	adapter <tag7 新的dapter加入> <to obj1>

static GSList *adapters
	adapter <tag15> <tp obj1>

db->notify_list <obj4>
struct notify *notify <tag19>
	->service_added = gatt_db_service_added
	->service_removed = gatt_db_service_removed
	->user_data = database <to obj3>

struct notify *notify <tag23> 
	->service_added = services_modified
	->service_removed = services_modified
	->user_data = database <to obj3>

struct btd_adapter *adapter; <obj1> <tag8>
	->system_name <tag12>
	->major_class <tag12>
	->minor_class <tag12>
	->dev_id = 0  <tag9>
	->struct mgmt *mgmt = mgmt_master<to obj2>
	->pincode_requested = false <tag9>
	/* Ongoing and pending auths */
	->GQueue *auths; <tag10>
	/* controller class of device */
	->uint32_t dev_class; <tag11>
	->name; <tag11> <tag55>
	->short_name <tag55>
	->supported_settings
	->manufacturer
	/* controller Bluetooth address */
	->bdaddr_t bdaddr;<tag13>
	/* address type */
	->uint8_t bdaddr_type = BDADDR_BREDR <tag14>
	->struct btd_gatt_database *database; <tag16> <to obj3>
	->drivers <tag24> <list>
	->profiles <tag25>
	/* Devices structure pointers */
	->GSList *devices; <to obj5 tag35> <to obj9 tag65>
	->struct bearer_state bredr_state;
		->bool paired; <true tag36>
		->bool bonded; <true tag39>
		->bool connected;
		->bool svc_resolved; <true tag37>
	/* Devices to connect when found */
	->GSList *connect_list; <add obj5 tag47 tag50> 
	/* Connected devices */
	//这里才是已连接的设备list
	->GSList *connections; <add obj9 tag66>
	->gboolean initialized; <true tag54>

struct btd_gatt_database *database <obj3> <tag20>
	->struct gatt_db *db; <tag21> <obj4>

//link key 队列
GSList *keys;
	key_info <tag26>

//根据蓝牙配对产生的info文件,产生的device.
struct btd_device *paired_device; <tag29> <obj5>
	->char		*path; <tag28>
	->bdaddr_t	bdaddr; <tag30>
	->struct btd_adapter	*adapter; <tag31> <to obj1>
	->bool		temporary = <true tag32> <false tag34>
	->GSList		*uuids; <add member tag33>
	/* List of btd_service */
	->GSList		*services;<add obj6 tag52>

struct btd_service *service; <tag42> <obj6>
	->struct btd_device	*device; <obj5> <tag44>
	->struct btd_profile	*profile; <tag45>
	->btd_service_state_t	state; <BTD_SERVICE_STATE_UNAVAILABLE tag46> <BTD_SERVICE_STATE_DISCONNECTED tag49>
									<BTD_SERVICE_STATE_CONNECTING tag80> <BTD_SERVICE_STATE_CONNECTED tag94>

//扫描时产生的device.
struct btd_device *scan_device <tag56> <obj9>
	->bdaddr_t	bdaddr; <tag59>
	->uint8_t		bdaddr_type; <tag57>
	->char		*path;
	->bool		bredr; <true tag58>
	->bool		le;
	->struct btd_adapter	*adapter; <to obj1 tag60>
	->bool		temporary = <true tag61> 
	->int8_t		rssi; <tag68>
	->eir_uuids <tag70>
	->sdp_list_t	*tmp_records; <to list3 tag73>
	->struct bearer_state bredr_state;
		->bool paired; <true tag69>
		->bool bonded;  <true tag67>
		->bool connected;
		->bool svc_resolved; <true tag77>
	/* List of btd_service */
	->GSList		*services; <add tag75> <obj10>// 支持的且probed的profile 加入list
	/* Pending services */
	->GSList		*pending; <add obj10 tag79>

struct browse_req *req <tag70> 
	->struct btd_device *device <to obj9>
	->sdp_list_t *records; <add tag71> <list3>
	->GSList *profiles_added; <add tag74>

struct headset *hs <tag98>
	=>headset_state_t state; <HEADSET_STATE_CONNECTING tag96> <HEADSET_STATE_CONNECTED tag97>

/*
关键结构体和队列说明:

1. static GSList *plugins;
	bluez支持的profile插件队列.
2. static GList *adapter_list
	蓝牙适配器队列.
3. struct btd_adapter *adapter;
	蓝牙适配器结构体.
4. struct btd_device *device;
	蓝牙设备结构体.

部分文件说明:
1. /etc/bluetooth/main.conf
	蓝牙适配器的默认配置文件.
2. /lib/bluetooth/<蓝牙适配器地址>/settings
	蓝牙适配器的个性化配置文件.
3. /lib/bluetooth/<蓝牙适配器>/cache/<蓝牙设备地址>
	扫描和配对蓝牙设备时产生的文件. 保存蓝牙设备name, UUID信息.
4. /lib/bluetooth/<蓝牙适配器>/<蓝牙设备地址>/info
	配对蓝牙设备成功时产生的文件. 保存蓝牙设备name,SDP数据(包含UUID,protocol,profile name各种详细信息),
	以及link key.

bluetoothd 总体初始化流程:
1. 解析/etc/bluetooth/main.conf文件, 将设置保存到main_opts结构体.
2. 	产生dbus目录: "/org/bluez", "org.bluez.AgentManager1",
	产生dbus目录: "/org/bluez", "org.bluez.ProfileManager1",
3. 对内置的plugin, 和加载位于/lib/bluetooth/xxx.so 的plugin, 进行初始化, 即执行plugin的init()函数.
	将这些profile plugin安装其profile自己配置的优先级, 加入profile队列.
4. 获得内核蓝牙mgmt层的版本, mgmt支持的命令.
5. 获取内核蓝牙的蓝牙adapter(适配器)列表.
6. 获取蓝牙adpater硬件信息, 注册本adapter的sdp数据.
7. 使用 STORAGEDIR/<adapter 设备地址>/settings 文件, 单独配置该adapter.
	main.conf是全局adapter的配置. 该settings是指定adapter的.
8. 之前plugin->init()初始化时, 通过btd_register_adapter_driver()函数注册了
   该plugin的struct btd_adapter_driver adapter_driver.
   现在该步骤就是执行plugin->adapter_driver->probe() 功能.
   该probe功能主要是想bluez注册一些服务, 例如该plugin(profile)的sdp数据, 或者是注册一些回调函数等.
9. 之前plugin->init()初始化时, 通过btd_profile_register()函数注册了
	该plugin的struct btd_profile *profile.
	现在就是要执行plugin->profile->adapter_probe()功能.
10. 我不清楚, 两个probe的执行位置如此靠近. adpater_probe比probe还多了一个参数, 按道理两者应该可以
	相互替换?
	plugin->adapter_driver->probe()(struct btd_adapter *adapter)
	plugin->profile->adapter_probe(struct btd_profile *p,struct btd_adapter *adapter)
11. 若是之前有配对成功的蓝牙设备, 则会产生info文件.
12. 读取 STORAGEDIR/<adapter 设备地址>/<蓝牙设备地址>/info 文件.
	获得link key, 同时将<蓝牙设备地址>目录名转为蓝牙地址,保存进key_info结构体.
	显然后面是根据key_info->bdaddr蓝牙地址,来选择link key, 以完成与对面蓝牙设备的自动连接.
	而不是每次都要pair配对.
13. 从info文件中获取设备名, 并保存到device->name
	从info文件中获取获取蓝牙设备提供的profile列表(uuids)
	这里简单说明PSM和UUID的区别.
	PSM是描述protocol的类型, 例如rfcomm
	每个protocol可以动态申请一个l2cap的通道, 该通道编号称为CID
	profile是建立在protocol上的.例如 hfp建立在rfcomm上.
	uuid就是该profile的编号, 例如HFP profile的短UUID为0x111E.
14.	加载STORAGEDIR/<adapter 地址>/<BLE设备地址>/attributes文件.
	从文件里读取UUID.
	我的文件系统里面没有该文件, 我之前确实连接过BLE设备了.
	应该需要BLE设备地址是static类型才可能有?
15. 将所有蓝牙设备的link key以及对应的设备地址, 发送给linux内核的蓝牙mgmt层.
	显然后续蓝牙host连接蓝牙设备时, APP层的bluez不需要有将link key传个内核层的步骤,
	这里就已经将link key全部传给内核层了.
	也确实是这样, 后续蓝牙设备主动连接host时, bluez也不见有任何link key相关的步骤.
16. 刚刚通过info文件获取已配对的蓝牙设备支持的profile的UUIDs.
	然后遍历该bluez已经支持的profile,
	通过对比支持的profile->remote_uuid和蓝牙设备支持的profile的uuid,
	决定是否执行profile->device_probe(). 这里的device_probe()就像linux驱动的设备probe,
	主要就是创建该设备的结构体,用结构体保存设备的各种信息.
17. 设置host自动连接device,
	需要设置probe->auto_connect=true, 和profile->accept函数指针.
	之前会将需要自动连接的蓝牙设备的地址发送给mgmt层.
	该功能我没有使用过, 不知道是否有效?
18. 设置adapter名字, 
	adapter->stored_alias优先作为adapter的名字, 该值由STORAGEDIR/<adapter 设备地址>/settings配置.
	stored_alias为空则使用adapter->system_name, system_name是由main.conf配置的.
	setting文件是每个adapter单独的配置, 相比main.conf的通用配置, 优先级显然是要更高.

执行蓝牙设备扫描的大致流程:
1. 向mgmt层发送MGMT_OP_START_DISCOVERY开始扫描命令.
2. 将扫描到的蓝牙设备的名字, 写入 <adapter 地址>/cache/<设备地址> 文件内.

配对蓝牙设备大致流程:
1. 要配对的蓝牙设备设置为非临时设备,使用mgmt命令, 将此蓝牙设备加入白名单.
2. 若此时host正在扫描, 则关闭扫描功能.
3. 向mgmt层发送MGMT_OP_PAIR_DEVICE命令, 开始配对蓝牙设备.
4. 配对过程中link key是双方的蓝牙控制器的协商结果, 不需要软件代码参与,
	协商出link key后会返回给mgmt,然后又传个bluez, bluez注册了"获得link key"的事件的回调函数
	new_link_key_callback().
5. new_link_key_callback() 执行以下操作:
	5.1 往 lib/bluetoothd/<adaper 地址>/<设备地址>/info 文件内写入link_key信息
	5.2 创建sdp连接,去获取对方蓝牙设备支持的profile. 回调函数是browse_cb().
	5.3 之前会调用suspend_discovery()关闭扫描. 现在恢复回去. 如果真的开了扫描的话.
6. 获取蓝牙设备的sdp数据后, 就会执行回调函数browse_cb().
	6.1browse_cb()解析蓝牙设备的sdp数据, 找到该设备支持的所有profile的UUID, 将这些UUID与
	6.2bluez支持的所有profile的UUID对比, 相同则执行该profile plugin的device_probe()函数.
	6.3最后, browse_cb()执行store_device_info()函数, 将sdp内获取的name, services(uuid)等数据
	写入/lib/bluetooth/<adaper 地址>/<蓝牙设备地址>/info文件内.

host主动连接蓝牙设备的大致流程:
1. 在匹配阶段,就已经知道该蓝牙设备支持什么profile了.
	现在就按照profile的优先级, 执行支持的profile的connect()函数.
2. profile->connect()的工作说明:
	2.1. 当前阶段双方蓝牙控制器已经建立加密连接, 后续就可以建立某个protocol(例如rfcomm) l2cap通道连接了. 
		connec()函数就是要建立该protocol的l2cap连接.
	2.2. protocol(例如rfcomm)连接成功后, 就建立基于该protocol的profile(例如hfp)的连接.

蓝牙device主动连接host情况的大致说明:
1. 在bluetoothd的初始化阶段, 会执行plugin->adapter_driver->probe()(struct btd_adapter *adapter)函数,
	该probe函数会注册sdp数据到bluez的sdp数据库内. 当其他蓝牙设备扫描本机设备时,或主动与本机配对时,
	就是会主动地申请获取本机的sdp数据.
	本机的sdp数据记录本机支持的profile, 例如本机支持hfp, 那么就会向sdp数据库注册hfp ag的sdp数据.
2. 以hfp为例. 蓝牙设备主动与本机建立rfcomm 端口为x的连接.
	plugin->adapter_driver->probe()之前会建立对rfcomm 端口x的监听.
	那么监听到连接后, host就会开始响应蓝牙设备的ATT命令, 建立hfp的连接.
	
以HFP为例, 描述host主动连接蓝牙设备的流程:
1. profile->connect() 对应hfp的hfp_connect()函数,取出该蓝牙设备的sdp数据,
	获得rfcomm的CID(channel ID). CID表明要在l2cap哪个channel上建立rfcomm protocol的连接.
	使用CID建立rfcomm连接.
2. 监听rfcomm通道的数据, 根据不同的ATT命令执行不同的函数.
	根据HFP规范, 对必要的ATT进行回复, 完成hfp连接的建立.
 */

main()
	=>__btd_log_init(option_debug, option_detach); //初始化log文件.
	=>parse_config(main_conf); //解析main.conf文件, 将设置保存到main_opts结构体.
	=>adapter_init(void)
		=>dbus_conn = btd_get_dbus_connection();
		=>mgmt_master = mgmt_new_default(); <tag5>
		//获取linux内核蓝牙协议栈的mgmt层的版本信息.
		=>mgmt_send(mgmt_master, MGMT_OP_READ_VERSION,MGMT_INDEX_NONE, 0, NULL,read_version_complete, NULL, NULL)
	=>btd_agent_init(); //产生dbus目录: "/org/bluez", "org.bluez.AgentManager1",
	=>btd_profile_init(); //产生dbus目录: "/org/bluez", "org.bluez.ProfileManager1",
	//显然,did和sdp profile是经典蓝牙专属的. BLE是att.
	=>if (main_opts.mode != BT_MODE_LE)//判断当前模式为经典蓝牙
		=>if (option_compat == TRUE){} // 判断是否为兼容模式, 则SDP的数据库保存在应用层.否则在内核层, 性能更高.
			=>start_sdp_server(sdp_mtu, sdp_flags);
				//建立本蓝牙机器的sdp server record.有其他蓝牙设备想获取本机的sdp服务时,
				//就可以将这些server record发送给它.
				=>init_server(mtu, master, compat) 
			//注册did数据,又或称pnp, 类似usb的vid和pid. 让对方设备通过did数据直接判断你的设备,而不通过sdp的各种profile.
			=>register_device_id(main_opts.did_source,main_opts.did_vendor,main_opts.did_product,main_opts.did_version);
	/* 可以通过bluetoothd --plugin 或 -p 指定要enbale 的plugin.
	 * 可以通过bluetoothd --noplugin 或 -P 指定要disabale 的plugin.
	 * 若没有指定, 则option_plugin and option_noplugin == NULL*/
	=>plugin_init(option_plugin, option_noplugin);
		=>for (i = 0; __bluetooth_builtin[i]; i++) //遍历所有的内建plugin.
			=>add_plugin(NULL,  __bluetooth_builtin[i]);//按plugin优先级加入 plugins队列.
				=>plugins = g_slist_insert_sorted(plugins, plugin, compare_priority);
		//PLUGINDIR目录为home/xx/ bluetooth/build/lib/bluetooth/plugins
		//加载*.so的动态plugin, plugin名为xxx.so, 不能为libxxx.so
		=>dir = g_dir_open(PLUGINDIR, 0, NULL);
			=>add_plugin(handle, desc) //加入plugins 队列.
		=>for (list = plugins; list; list = list->next) //遍历plugins队列上的所有插件
			=>err = plugin->desc->init(); //执行初始化, hfp_init
			=>plugin->active = TRUE;
	=>rfkill_init();
	=>g_main_loop_run(event_loop); // while

main()=>adapter_init() send read_version request, callback:
read_version_complete
	//保持获取到的mgmt版本号.
	=>mgmt_version = rp->version;
	=>mgmt_revision = btohs(rp->revision);
	//请求获取mgmt层支持的命令.
	=>mgmt_send(mgmt_master, MGMT_OP_READ_COMMANDS,MGMT_INDEX_NONE, 0, NULL,read_commands_complete, NULL, NULL);
		//若是mgmt支持MGMT_OP_ADD_DEVICE命令, 则kernel_conn_control值为true.
		=>read_commands_complete()
			=>if (op == MGMT_OP_ADD_DEVICE)
				=>kernel_conn_control = true;//enabling kernel-side connection control
	//监听 新的adapter 加入, 然后执行index_added()
	=>mgmt_register(mgmt_master, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,index_added, NULL, NULL);
	//监听 adapter移除, 然后执行index_removed().
	=>mgmt_register(mgmt_master, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,index_removed, NULL, NULL);
	//获取adapter list.
	=>mgmt_send(mgmt_master, MGMT_OP_READ_INDEX_LIST,MGMT_INDEX_NONE, 0, NULL,read_index_list_complete, NULL, NULL)
		=>read_index_list_complete
			//获得 adapter的数量
			=>num = btohs(rp->num_controllers);
			//加入所有的adapter
			=>for (i = 0; i < num; i++) {
				//该adapter的编号
				=>index = btohs(rp->index[i]);
				=>index_added(index, 0, NULL, NULL);
					=>adapter = btd_adapter_new(index);
						//使用main_opts配置adapter.
						adapter->system_name = g_strdup(main_opts.name);
						adapter->major_class = (main_opts.class & 0x001f00) >> 8;
						adapter->minor_class = (main_opts.class & 0x0000fc) >> 2;
						adapter->modalias = bt_modalias(main_opts.did_source,
											main_opts.did_vendor,
											main_opts.did_product,
											main_opts.did_version);
						adapter->discoverable_timeout = main_opts.discovto;
						adapter->pairable_timeout = main_opts.pairto;
					//新的adapter加入 adapter_list队列.
					=>adapter_list = g_list_append(adapter_list, adapter);
					=>mgmt_send(mgmt_master, MGMT_OP_READ_INFO, index, 0, NULL,read_info_complete, adapter, NULL)

//index_added() 添加新的adapter后会获取该adapter的信息.这里是callback
read_info_complete
	//保持adapter 硬件信息
	adapter->dev_class = rp->dev_class[0] | (rp->dev_class[1] << 8) |
						(rp->dev_class[2] << 16); <tag11>
	adapter->name = g_strdup((const char *) rp->name); <tag11>
	adapter->short_name = g_strdup((const char *) rp->short_name);

	adapter->manufacturer = btohs(rp->manufacturer);

	adapter->supported_settings = btohl(rp->supported_settings);
	adapter->current_settings = btohl(rp->current_settings);
	=>clear_uuids(adapter);
		=>mgmt_send(adapter->mgmt, MGMT_OP_REMOVE_UUID,
							adapter->dev_id, sizeof(cp), &cp,clear_uuids_complete, adapter, NULL)
			=>clear_uuids_complete() //回调. 没有什么有意义的操作..
	=>clear_devices(adapter);
		mgmt_send(adapter->mgmt, MGMT_OP_REMOVE_DEVICE,
							adapter->dev_id, sizeof(cp), &cp,clear_devices_complete, adapter, NULL)
		=>clear_devices_complete() //回调. 没有什么有意义的操作..
	=>bacpy(&adapter->bdaddr, &rp->bdaddr);
	=>if (!(adapter->supported_settings & MGMT_SETTING_LE))
		=>adapter->bdaddr_type = BDADDR_BREDR;
	=>switch (main_opts.mode) { //BT_MODE_DUAL==0. 为默认配置.并且我没有通过main.conf去配置mode成员.
	=>case BT_MODE_DUAL:
		=>if (missing_settings & MGMT_SETTING_BREDR)
			=>set_mode(adapter, MGMT_OP_SET_BREDR, 0x01);
				=>mgmt_send(adapter->mgmt, opcode,
								adapter->dev_id, sizeof(cp), &cp,set_mode_complete, adapter, NULL)
					=>set_mode_complete()
						=>settings_changed(adapter, settings)//更新dbus上的属性状态. power connect等.
	=>if (adapter->supported_settings & MGMT_SETTING_PRIVACY)
		//设置隐私策略.
		=>set_privacy(adapter, main_opts.privacy);
			=>mgmt_send(adapter->mgmt, MGMT_OP_SET_PRIVACY,
								adapter->dev_id, sizeof(cp), &cp,set_privacy_complete, adapter, NULL)
				=>set_privacy_complete(). //do nothing
	=>adapter_register(adapter);
		// hci0
		=>adapter->path = g_strdup_printf("/org/bluez/hci%d", adapter->dev_id);
		//注册dbus 路径.
		//#define ADAPTER_INTERFACE	"org.bluez.Adapter1"
		///org/bluez/hci0
		=>g_dbus_register_interface(dbus_conn,adapter->path, ADAPTER_INTERFACE,
								adapter_methods, NULL,adapter_properties, adapter,adapter_free)
		//加入adapers队列, 之前adapter还接入了adapter_list队列. 两队列区别?
		=>adapters = g_slist_append(adapters, adapter); <tag15>
		=>adapter->database = btd_gatt_database_new(adapter);
			//监听 l2cap层的 ATT_CID(0x4)通道的数据, for BLE
			=>database->le_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &gerr,BT_IO_OPT_SOURCE_BDADDR, addr,
									BT_IO_OPT_SOURCE_TYPE,btd_adapter_get_address_type(adapter),
									BT_IO_OPT_CID, ATT_CID,BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,BT_IO_OPT_INVALID);
			//监听 PSM值为ATT_PSM(0x1F)的通道的数据, FOR BLE.
			//即建立在CID(channel ID)为4的通道上的, 协议(PSM)为BLE ATT的数据.
			=>database->l2cap_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &gerr,BT_IO_OPT_SOURCE_BDADDR, addr,
									BT_IO_OPT_PSM, ATT_PSM,BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,BT_IO_OPT_INVALID);
			// 注册GATT的 dbus目录 , gatt为att的上层协议.
			//#define GATT_MANAGER_IFACE	"org.bluez.GattManager1"
			//adapter_get_path(adapter) /org/bluez/hci0
			=>g_dbus_register_interface(btd_get_dbus_connection(),adapter_get_path(adapter),
										GATT_MANAGER_IFACE,manager_methods, NULL, NULL,database, NULL)
			=>register_core_services(database);
				//其他设备使用sdp与本机器通讯时, 本机器将下面注册的信息返回给其他设备.
				=>populate_gap_service(database);
					=>Add the GAP service
					=>Add Device Name characteristic.
					=>Add Device Appearance characteristic.
				=>populate_gatt_service(database);
					=>Add the GATT service
					=>Add GATT_CHARAC_SERVICE_CHANGED
			//将gatt_db_service_added notify加入db的notify_list队列
			=>database->db_id = gatt_db_register(database->db, gatt_db_service_added,
											gatt_db_service_removed,database, NULL);
		//将services_modified notify加入db的notify_list队列
		=>adapter->db_id = gatt_db_register(db, services_modified,services_modified,adapter, NULL);
		=>load_config(adapter);
			=> //在STORAGEDIR/<adapter 设备地址>/settings 文件里, 可以配置adapter的
			=>adapter->pairable_timeout, adapter->stored_alias, adapter->stored_discoverable
			=>adapter->discoverable_timeout
			=>//之前使用main.conf是配置所有的adapter, 这里是使用adapter的设备地址, 有单独的配置.
		=>load_drivers(adapter);
			=>for (l = adapter_drivers; l; l = l->next){
				probe_driver(adapter, l->data); }
					//这里的driver是通过btd_register_adapter_driver()函数注册到 adapter_drivers队列的.
					//btd_register_adapter_driver()函数会由plugin代码调用, 来注册一些callback,
					//或者是sdp的server record.
					//例如 autopair的autopair_probe
					=>err = driver->probe(adapter); //执行plugin的probe().
					// 将这个执行成功的driver加入 adapter->drivers队列.
					=>adapter->drivers = g_slist_prepend(adapter->drivers, driver);
		=>btd_profile_foreach(probe_profile, adapter);
			//
			=>for (l = profiles; l != NULL; l = next) {
				func(profile, data);}
				=>probe_profile(profile,data)
					//调用plugin的adapter_probe()函数.这些函数指针都在plugin->init()函数被注册.
					=>profile->adapter_probe(profile, adapter); //hfp_server_probe
					=>adapter->profiles = g_slist_prepend(adapter->profiles, profile);
			=>for (l = ext_profiles; l != NULL; l = next) { //不懂.
				=>func(&profile->p, data); 				  }
		=>clear_blocked(adapter);
			=>btd_adapter_unblock_address(adapter, BDADDR_ANY, 0);
				=>mgmt_send(adapter->mgmt, MGMT_OP_UNBLOCK_DEVICE,adapter->dev_id, sizeof(cp), &cp,NULL, NULL, NULL)
		=>load_devices(adapter);
			//info文件在配对成功时产生. 最重要的作用是保存link key.
			=>//读取STORAGEDIR/<adapter 设备地址>/<蓝牙设备地址>/info.
				//获得link key, 同时将<蓝牙设备地址>目录名转为蓝牙地址,保存进key_info结构体.
				//显然后面是根据key_info->bdaddr蓝牙地址,来选择link key, 以完成与对面蓝牙设备的自动连接.
				//而不是每次都要pair配对.
				=>key_info = get_key_info(key_file, entry->d_name); 
				=>keys = g_slist_append(keys, key_info); //加入keys队列.
				=>ltk_info = get_ltk_info(key_file, entry->d_name, bdaddr_type);
				=>device = device_create_from_storage(adapter, entry->d_name, key_file);
					=>device = device_new(adapter, address);
						//path == <adapter 地址>/dev_<蓝牙设备地址>
						=>device->path = g_strdup_printf("%s/dev_%s", adapter_path, address_up);
						//将path中蓝牙设备地址的:号替换为_号.
						=>g_strdelimit(device->path, ":", '_');
						//设置设备地址.
						=>str2ba(address, &device->bdaddr);
						//注册该蓝牙设备的dbus路径: 
						//#define DEVICE_INTERFACE	"org.bluez.Device1"
						=>g_dbus_register_interface(dbus_conn,device->path, DEVICE_INTERFACE,
													device_methods, NULL,device_properties, device,device_free)
						=>device->adapter = adapter;
						=>device->temporary = true;
					//删除掉info文件中的General中的SDPServices和GATTServices
					=>convert_info(device, key_file);
					=>load_info(device, srcaddr, address, key_file);
						//从info文件中获取设备名, 并保存到device->name
						=>str = g_key_file_get_string(key_file, "General", "Name", NULL);
						=>strcpy(device->name, str);
						=>device->alias = g_key_file_get_string(key_file, "General", "Alias",NULL);
						=>str = g_key_file_get_string(key_file, "General", "Class", NULL);
						=>device->class = class;
						//获取蓝牙设备是经典蓝牙orBLE
						=>techno = g_key_file_get_string_list(key_file, "General","SupportedTechnologies", NULL, NULL);
						=>device->bredr = true;
						=>device->bdaddr_type = BDADDR_BREDR;
						//获得与该设备的连接参数, 后续这些参数会发送到蓝牙mgmt层.
						=>param = get_conn_param(key_file, entry->d_name, bdaddr_type);
						=>device->trusted = g_key_file_get_boolean(key_file, "General","Trusted", NULL);
						//若blocked为true,则断开设备连接
						=>blocked = g_key_file_get_boolean(key_file, "General", "Blocked", NULL);
						=>if (blocked) device_block(device, FALSE);
						//获取蓝牙设备提供的profile列表.
						//PSM是描述protocol的类型, 例如rfcomm
						//每个protocol可以动态申请一个l2cap的通道, 该通道编号称为CID
						//profile是建立在protocol上的.例如 hfp建立在rfcomm上.
						//uuid就是该profile的编号, 例如HFP profile的短UUID为0x111E.
						=>uuids = g_key_file_get_string_list(key_file, "General", "Services",NULL, NULL);
						=>load_services(device, uuids);
							=>device->uuids = g_slist_insert_sorted(device->uuids,g_strdup(*uuid),bt_uuid_strcmp);
						/* Discovered services restored from storage */
						=>device->bredr_state.svc_resolved = true;
					//加载STORAGEDIR/<adapter 地址>/<BLE设备地址>/attributes文件.
					//载入UUID.
					//我的文件系统里面没有该文件, 应该需要BLE设备地址是static类型才可能有?
					=>load_att_info(device, srcaddr, address)
				=>btd_device_set_temporary(device, false); <tag34>
					=>adapter_whitelist_add(device->adapter, device);
					=>store_device_info(device);
						//在空闲时会执行 store_device_info()函数, 将[General]下的name, services等数据
						//写入info文件.
						=>device->store_id = g_idle_add(store_device_info_cb, device);
							=>store_device_info_cb
				=>adapter->devices = g_slist_append(adapter->devices, device);
				//下面这句list add 好像没有什么意义?
				=>added_devices = g_slist_append(added_devices, device);
				=>device_set_paired(device, BDADDR_BREDR);
					=>dev->bredr_state.paired = true
					=>g_dbus_emit_property_changed(dbus_conn, dev->path,DEVICE_INTERFACE, "Paired");
			//将所有蓝牙设备的link key以及对应的设备地址, 发送给linux内核的蓝牙mgmt层.
			=>load_link_keys(adapter, keys, main_opts.debug_keys);
				=> .....
				=>mgmt_send(adapter->mgmt, MGMT_OP_LOAD_LINK_KEYS,adapter->dev_id, cp_size, cp,
									load_link_keys_complete, adapter, NULL);
					=>load_link_keys_complete() //do nothing
			//将从info文件里获取的每个设备的连接参数, 发送给蓝牙mgmt层.
			=>load_conn_params(adapter, params);
				=>mgmt_send(adapter->mgmt, MGMT_OP_LOAD_CONN_PARAM, adapter->dev_id,
								cp_size, cp, load_conn_params_complete, adapter, NULL);
					=>load_conn_params_complete() //do nothing
			//奇怪的用法, 使用probe_devices()函数处理added_devices列表里所有的device.
			=>g_slist_free_full(added_devices, probe_devices);
				=>probe_devices(void *user_data)
					=>device_probe_profiles(device, btd_device_get_uuids(device));
						=>btd_profile_foreach(dev_probe, &d);
							//遍历该bluez已经支持的profile,
							//通过对比支持的profile->remote_uuid和蓝牙设备支持的profile的uuid,
							//决定是否执行profile->device_probe()
							=>for (l = profiles; l != NULL; l = next) {
								=>dev_probe(profile, data); 		  }
									=>probe_service(d->dev, p, d->uuids);
										=>device_match_profile(device, profile, uuids)
											=>g_slist_find_custom(uuids, profile->remote_uuid,bt_uuid_strcmp)
										=>service = service_create(device, profile);
											=>service->device = device; //蓝牙设备
											=>service->profile = profile;//匹配到的bluez支持的profile.
											=>service->state = BTD_SERVICE_STATE_UNAVAILABLE;
										=>service_probe(service)
											=>service->profile->device_probe(service); //hfp_device_probe
											=>change_state(service, BTD_SERVICE_STATE_DISCONNECTED, 0);
										//显然仅设置auto_connect=true还不够, 还要设置accept函数指针.
										=>if (profile->auto_connect && profile->accept)
											=>device_set_auto_connect(device, TRUE);
												//bluez的profile支持自动连接, 而蓝牙设备支持该profile,
												//就将该蓝牙设备的设备地址发送给mgmt层.
												=>adapter_auto_connect_add(device->adapter, device);
													=>cp.addr.type = bdaddr_type;
													=>mgmt_send(adapter->mgmt, MGMT_OP_ADD_DEVICE,
														adapter->dev_id, sizeof(cp), &cp, add_device_complete,
														adapter, NULL);
													//device加入adaper->connect_list
													=>g_slist_append(adapter->connect_list, device);
												//device加入adaper->connect_list,即是不支持auto_connect,
												//也还是要加入connect_list
												=>adapter_connect_list_add(device->adapter, device);
									//将包含profile信息的service结构体, 加入device->services队列.
									=>d->dev->services = g_slist_append(d->dev->services, service);
									//没看懂. uuids来源于device->uuids.
									//该函数将uuids加入device->uuid队列, 通知dbusuuid有改变.
									//没找到uuid改变的地方?
									=>device_add_uuids(device, uuids);
		//end load_devices(adapter);
		=>adapter->initialized = TRUE;
		=>//后面是注册各种mgmt事件的回调函数,非常多.
		//配置adapter的class,发送给mgmt层
		=>set_dev_class(adapter);
			//adapter->major_class and minor_class的值由main.conf配置.
			=>cp.major = adapter->major_class & 0x1f;
			=>cp.minor = adapter->minor_class << 2;
			=>mgmt_send(adapter->mgmt, MGMT_OP_SET_DEV_CLASS,adapter->dev_id, sizeof(cp), &cp,
							set_dev_class_complete, adapter, NULL)
		//设置adapter名字, 
		//adapter->stored_alias优先作为name, 该值由STORAGEDIR/<adapter 设备地址>/settings配置.
		//adapter->system_name随后, 由main.conf配置.
		//显然setting文件是每个adapter单独的配置, 相比main.conf的通用配置, 优先 级当然高.
		=>set_name(adapter, btd_adapter_get_name(adapter));
			=>mgmt_send(adapter->mgmt, MGMT_OP_SET_LOCAL_NAME,adapter->dev_id, sizeof(cp), &cp,
							set_local_name_complete, adapter, NULL)
				=>set_local_name_complete()
					//mgmt层返回的name, 赋值为adapter->name. 同时更新dbus上adapter的名字.
					=>local_name_changed_callback()
						=>adapter->name = g_strdup((const char *) rp->name);
		=>set_mode(adapter, MGMT_OP_SET_BONDABLE, 0x01);
		=> if (adapter->current_settings & MGMT_SETTING_POWERED) //表明adapter已上电.感觉更多是软件概念.
			=>adapter_start(adapter);
				=>g_dbus_emit_property_changed(dbus_conn, adapter->path,ADAPTER_INTERFACE, "Powered");

//使能扫描
//APP call
g_dbus_proxy_call_sync(adapter_proxy, "StartDiscovery" ,NULL,G_DBUS_CALL_FLAGS_NONE,-1,NULL,&error)
//bluez callback
{ GDBUS_METHOD("StartDiscovery", NULL, NULL, start_discovery) } // src/adapter.c
start_discovery()
	//判断是否已经在搜索状态, true则返回繁忙.
	=>is_discovering = get_discovery_client(adapter, sender, &client);
	=>update_discovery_filter(struct btd_adapter *adapter)
		=>trigger_start_discovery(adapter, 0);
			=>cancel_passive_scanning(struct btd_adapter *adapter)
			=>g_timeout_add_seconds(delay, start_discovery_timeout, adapter)
				=>start_discovery_timeout(gpointer user_data)
					=>mgmt_send(adapter->mgmt, MGMT_OP_START_DISCOVERY,adapter->dev_id, sizeof(cp), &cp,
											start_discovery_complete, adapter, NULL);
						=>start_discovery_complete()
							//更新dbus 属性状态.
							=>g_dbus_emit_property_changed(dbus_conn, adapter->path,ADAPTER_INTERFACE, "Discovering");

//在bluetoothd初始化时, 注册的mgmt事件callback.
discovering_callback()
	=>//我这边运行时的逻辑是 do nothing

//在bluetoothd初始化时, 注册的mgmt事件callback.
device_found_callback()
	=>update_found_devices(adapter, &ev->addr.bdaddr, ev->addr.type,ev->rssi, confirm_name, legacy,
											flags & MGMT_DEV_FOUND_NOT_CONNECTABLE,eir, eir_len);
		//解析mgmt层返回的设备eir(EXTENDED INQUIRY RESPONSE额外查询详细)信息(data参数), 保持到eir_data结构体
		//eir就是比一般的查询多了许多信息, 有rssi,支持的profile等信息.需要被查询的蓝牙设备提供了自身的eir数据.
		=>eir_parse(&eir_data, data, data_len);
		//从adapter->devices中查找相同地址的设备. 若是新的蓝牙设备, 显然返回NULL.
		=>dev = btd_adapter_find_device(adapter, bdaddr, bdaddr_type);
			=>list = g_slist_find_custom(adapter->devices, &addr,device_addr_type_cmp);
		=>if (!dev) 													 {
			=>dev = adapter_create_device(adapter, bdaddr, bdaddr_type); }
				=>device = device_create(adapter, bdaddr, bdaddr_type);
					=>device = device_new(adapter, dst);
						=>device->path = g_strdup_printf("%s/dev_%s", adapter_path, address_up);
						//将蓝牙设备地址的:号替换为_号
						=>g_strdelimit(device->path, ":", '_');
						//保持蓝牙设备地址
						=>str2ba(address, &device->bdaddr);
						//就算是扫描出来的临时蓝牙设备, 有能有dbus路径
						//#define DEVICE_INTERFACE	"org.bluez.Device1"
						=>g_dbus_register_interface(dbus_conn,device->path, DEVICE_INTERFACE,
										device_methods, NULL,device_properties, device,device_free)
						=>device->adapter = adapter;
						=>device->temporary = true;
					=>device->bdaddr_type = bdaddr_type;
					=>device->bredr = true; OR device->le = true;
					//从STORAGEDIR/<adaper 地址>/cache/<蓝牙设备地址> 文件内,获取name属性.
					//在后续代码里,会使用函数在cache目录下产生名为蓝牙设备地址的文件.
					//若是此时有该文件, 表明是重复扫描到的设备?
					=>str = load_cached_name(device, src, dst);
					=>strcpy(device->name, str);
				//连临时设备也可以加入devices队列
				=>adapter->devices = g_slist_append(adapter->devices, device);
		//看来需要有名蓝牙设备才能在cache目录下产生文件.
		=>if (eir_data.name != NULL && eir_data.name_complete)
			=>device_store_cached_name(dev, eir_data.name);
				//example: 68:89:5B:01:28:23/cache/C0:ED:E5:01:68:A2
				=>snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", s_addr, d_addr);
				=>create_file(filename, S_IRUSR | S_IWUSR);
				//只是在文件内写入设备名信息而已.
				=>g_key_file_set_string(key_file, "General", "Name", name);
		=>device_set_rssi(dev, rssi);
			=>device_set_rssi_with_delta(device, rssi, RSSI_THRESHOLD);
			=>device->rssi = rssi;
		=>device_add_eir_uuids(dev, eir_data.services);
			=>dev->eir_uuids = g_slist_append(dev->eir_uuids, g_strdup(str));
			=>g_dbus_emit_property_changed(dbus_conn, dev->path,DEVICE_INTERFACE, "UUIDs");

//配对 经典蓝牙设备
//APP call
g_dbus_proxy_call_sync(adapter_proxy, "Pair" ,NULL,G_DBUS_CALL_FLAGS_NONE,-1,NULL,&error)
//bluez callback
=>{ GDBUS_ASYNC_METHOD("Pair", NULL, NULL, pair_device) } // src/device.c
=>pair_device()
	//设置为非临时蓝牙设备, 并加入白名单
	=>btd_device_set_temporary(device, false);
		=>device->temporary = temporary;
		=>adapter_whitelist_add(device->adapter, device);
			=>mgmt_send(adapter->mgmt, MGMT_OP_ADD_DEVICE,adapter->dev_id, sizeof(cp), &cp,
												add_whitelist_complete, adapter, NULL);
				=>add_whitelist_complete() //do nothing
		=>//store_device_info(device); //to do 
	=>bonding = bonding_request_new(msg, device, bdaddr_type, agent);
	=>device->bonding = bonding;
	=>bonding->device = device;
	=>adapter_create_bonding(adapter, &device->bdaddr,BDADDR_BREDR, io_cap) //BR/EDR设备的配对. BLE的case这里忽略.
		=>suspend_discovery(adapter) // 关闭蓝牙扫描
			=>mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,adapter->dev_id, sizeof(cp), &cp,
													suspend_discovery_complete, adapter, NULL);
		//发起配对.
		=>adapter_bonding_attempt(adapter, bdaddr, addr_type, io_cap);
			=>mgmt_send(adapter->mgmt, MGMT_OP_PAIR_DEVICE,adapter->dev_id, sizeof(cp), &cp,
												pair_device_complete, data,free_pair_device_data);
			//配对超时的处理函数注册.
			=>g_timeout_add_seconds(BONDING_TIMEOUT,pair_device_timeout, data);

//配对前, 需要与对方蓝牙设备建立蓝牙控制器间的连接. 我称为l2cap层的连接.
connected_callback()
	//mgtm层会将蓝牙设备的eir数据返回, 这里处理eir数据.
	//怪哉,实际配对过程中没有获取eir的步骤?
	=>eir_parse(&eir_data, ev->eir, eir_len);
	=>adapter_add_connection(adapter, device, ev->addr.type);
		=>device_add_connection(device, bdaddr_type);
			//更新蓝牙设备的dbus属性
			=>g_dbus_emit_property_changed(dbus_conn, dev->path, DEVICE_INTERFACE,"Connected");
		=>adapter->connections = g_slist_append(adapter->connections, device);
	//将蓝牙设备名信息写进cache目录下的名为<蓝牙设备地址>的文件
	=>device_store_cached_name(device, eir_data.name);

//配对的流程是先建立蓝牙控制器间的无加密连接.
//后续控制器间协商出共享秘钥,该秘钥由蓝牙控制器加密后即为link key.
//因此该link key可以明文保持,因为只有控制器才可以解密出共享秘钥.
//该共享秘钥用于后续蓝牙控制器间建立加密连接. rfcomm等,还是所有的protocol都
//需要通讯在加密连接?
//所以配对的目的就要产生link key.
//new_link_key_callback()函数是控制器生成link key后需要我们APP层进行保存.
//等以后与蓝牙设备再进行连接时, 就可以不需要再次协商出共享秘钥, 直接提供link key,
//让控制器解密出共享秘钥, 就可以进行加密连接,从而开展后续的protocol连接.
new_link_key_callback()
	// 往 lib/bluetoothd/<adaper 地址>/<设备地址>/info 文件内写入link_key信息
	=>store_link_key(adapter, device, key->val, key->type, key->pin_len);
		=>snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info",adapter_dir(adapter), device_addr);
		//write link key infomation
		=>g_key_file_set_string(key_file, "LinkKey", "Key", key_str);
		=>g_key_file_set_integer(key_file, "LinkKey", "Type", type);
		=>g_key_file_set_integer(key_file, "LinkKey", "PINLength", pin_length);
		//创建info文件.
		=>create_file(filename, S_IRUSR | S_IWUSR);
	=>device_set_bonded(device, BDADDR_BREDR);
		=>device->bredr_state.bonded = true;
		=>btd_device_set_temporary(device, false);
	=>bonding_complete(adapter, &addr->bdaddr, addr->type, 0);
		=>device_bonding_complete(device, addr_type, status);
			=>device_set_paired(device, bdaddr_type);
				=>state->paired = true;
				=>g_dbus_emit_property_changed(dbus_conn, dev->path,DEVICE_INTERFACE, "Paired");
			=>device_browse_sdp(device, bonding->msg);
				=>bt_search_service(btd_adapter_get_address(adapter),
										&device->bdaddr, &uuid, browse_cb, req, NULL,req->sdp_flags);
					=>create_search_context(&ctxt, src, dst, uuid, flags);
						//创建sdp连接,去获取对方蓝牙设备支持的profile. 回调函数是browse_cb().
						=>sdp_connect(src, dst, SDP_NON_BLOCKING | flags);
		// 之前会调用suspend_discovery()关闭扫描. 现在回复回去. 如果真的开了扫描的话.
		=>resume_discovery(adapter);

//执行完new_link_key_callback(), 就会执行这个.
//配对的过程包括1.建立无加密连接 2.产生link key.
//刚刚已经获取link key, 配对过程就算完成了.
pair_device_complete()
	=>bonding_attempt_complete(adapter, &rp->addr.bdaddr, rp->addr.type,status)
		=>bonding_complete(adapter, bdaddr, addr_type, status);
			//state->paired 在new_link_key_callback()里被设置为true.
			//因此device_bonding_complete() do nothing
			=>device_bonding_complete(device, addr_type, status);
				=>if (state->paired) {
					return; }
			=>resume_discovery(adapter);

//sdp 搜索到了profile, 产生事件, 引起该callback.
connect_watch

//connect_watch()执行完, 就到这里了
search_process_cb

//多轮的search_process_cb()执行后:
search_completed_cb

//执行完search_completed_cb()后, browse_cb就执行了.
//输入参数就是 对方蓝牙设备的 sdp数据. 这里进行解析和保存.
browse_cb(recs)
static void browse_cb(sdp_list_t *recs, int err, gpointer user_data)
	=>update_bredr_services(req, recs);
		//导入xx/cache/<设备地址> 文件
		=>snprintf(sdp_file, PATH_MAX, STORAGEDIR "/%s/cache/%s", srcaddr,dstaddr);
		=>g_key_file_load_from_file(sdp_key_file, sdp_file, 0, NULL);
		=>sdp_get_service_classes(rec, &svcclass)
			//从sdp数据中,获取SDP_ATTR_SVCLASS_ID_LIST类型的字段, 即profile的uuid
			=>sdp_get_uuidseq_attr(rec, SDP_ATTR_SVCLASS_ID_LIST, seqp);
		//将uuid转换为128uuid, 保存为字符串
		=>profile_uuid = bt_uuid2string(svcclass->data);
		=>update_record(req, profile_uuid, rec)
			//将sdp数据中保存的profile的uuid 加入profiles_added队列.
			=>req->profiles_added = g_slist_append(req->profiles_added,g_strdup(uuid));
		//将recs记录的sdp数据 写入cache/<蓝牙设备地址> 文件内.
		=>store_sdp_record(sdp_key_file, rec);
			=>g_key_file_set_string(key_file, "ServiceRecords", handle_str, str);
		//这里是保存设备的ATT信息, 但我的是经典蓝牙设备, 非BLE,没有这些数据, So do nothing.
		=>store_primaries_from_sdp_record(att_key_file, rec);
	=>bt_search_service(btd_adapter_get_address(adapter),&device->bdaddr, &uuid,
										browse_cb, user_data, NULL,req->sdp_flags);
		//这里的与之前的browse_cb不是同一个函数.
		=>browse_cb(sdp_list_t *recs, int err, gpointer user_data)
			=>search_cb(recs, err, user_data);
				=>device_probe_profiles(device, req->profiles_added);
					=>btd_profile_foreach(dev_probe, &d);
						//遍历bluez支持的所有profile, 仅uuid匹配的profile才会被执行probe()
						=>for (l = profiles; l != NULL; l = next) {
							=>dev_probe(struct btd_profile *p, void *user_data)
								=>service = probe_service(d->dev, p, d->uuids);
									=>if (!device_match_profile(device, profile, uuids)) {return}
									=>service_probe(service)
										// 执行该uuid匹配成功的profile的device_probe() 函数.
										=>service->profile->device_probe(service);
										//判断是否支持自动连接
										=>if (profile->auto_connect && profile->accept)
											=>device_set_auto_connect(device, TRUE);
												=>device->auto_connect = enable;
												=>adapter_auto_connect_add(device->adapter, device);
													=>mgmt_send(adapter->mgmt, MGMT_OP_ADD_DEVICE,
															adapter->dev_id, sizeof(cp), &cp, add_device_complete,
															adapter, NULL);
					=>device_add_uuids(device, uuids);
						//sdp数据中找到的profile的uuid,
						//将这些profile的uuid加入 uuids队列
						=>device->uuids = g_slist_insert_sorted(device->uuids,g_strdup(l->data),bt_uuid_strcmp);
				=>device_svc_resolved(device, BROWSE_SDP, BDADDR_BREDR, err)
					=>state->svc_resolved = true;
					//在空闲时会执行 store_device_info()函数, 将[General]下的name, services(uuid)等数据
					//写入info文件.
					=>store_device_info(dev);
					//更新该蓝牙设备的dbus状. pair,connect等.
					=>browse_request_complete(req, browse_type, bdaddr_type, err);

// APP call
g_dbus_proxy_call_sync(adapter_proxy, "Connect" ,NULL,G_DBUS_CALL_FLAGS_NONE,-1,NULL,&error)
//bluez callback
=>{ GDBUS_ASYNC_METHOD("Connect", NULL, NULL, dev_connect) }, // src/device.c
=>dev_connect()
	=>connect_profiles(dev, bdaddr_type, msg, NULL);
		//判断adapter已经上电.
		=>if (!btd_adapter_get_powered(dev->adapter))
			=>if (adapter->current_settings & MGMT_SETTING_POWERED) return true;
		//将蓝牙设备支持的, 且bluez支持的, 所有保存在dev->services的profile,
		//按profile的优先级,加入dev->pending队列.
		=>dev->pending = create_pending_list(dev, uuid);
			=>for (l = dev->services; l != NULL; l = g_slist_next(l)) {
				dev->pending = g_slist_insert_sorted(dev->pending, service,service_prio_cmp); }
		=>connect_next(struct btd_device *dev)
			//调用dev->pending队列内所有的profile的connect()指针函数.
			=>while (dev->pending)
				=>btd_service_connect(service)
					=>profile->connect(service);//a2dp_sink_connect
					=>change_state(service, BTD_SERVICE_STATE_CONNECTING, 0);
						=>service->state = state;

//profile->connect():
hfp_connect(struct btd_service *service)
	=>rfcomm_connect(hs, NULL, NULL, NULL);
		=>get_records(hs, cb, user_data, cb_id);
			=>bt_search_service(btd_adapter_get_address(adapter),
										device_get_address(hs->btd_dev),&uuid,get_record_cb,hs, NULL, 0);
			=>headset_set_state(hs, HEADSET_STATE_CONNECTING);
				=>hs->state = state;

void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
	=>headset_set_channel(hs, record, p->svclass)
		=>sdp_get_access_protos(record, &protos)
		=>ch = sdp_get_proto_port(protos, RFCOMM_UUID);
		=>headset->rfcomm_ch = ch;
	=>rfcomm_connect(hs, NULL, NULL, NULL);
		=>hs->tmp_rfcomm = bt_io_connect(headset_connect_cb, hs,NULL, &err,
						BT_IO_OPT_SOURCE_BDADDR, &hs->src,BT_IO_OPT_DEST_BDADDR, &hs->dst,
						BT_IO_OPT_CHANNEL, hs->rfcomm_ch,BT_IO_OPT_INVALID);

// btio/btio.c
connect_cb(GIOChannel *io, GIOCondition cond,gpointer user_data)
	=>conn->connect(io, gerr, conn->user_data);
		=>headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
			=>hs->rfcomm = hs->tmp_rfcomm;
			=>g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,(GIOFunc) rfcomm_io_cb, hs);
			=>hs->slc = g_new0(struct headset_slc, 1);
				hs->slc->sp_gain = 15;
				hs->slc->mic_gain = 15;
				hs->slc->nrec = TRUE;
			=>if (hs->hfp_active) { return }

rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,struct headset *hs)
	=>fd = g_io_channel_unix_get_fd(chan);
	=>bytes_read = read(fd, buf, sizeof(buf) - 1);
	=>handle_event(hs, &slc->buf[slc->data_start]);
	=>for (ev = event_callbacks; ev->cmd; ev++) {
		=>if (!strncmp(buf, ev->cmd, strlen(ev->cmd))) return ev->callback(hs, buf);

//rfcomm_io_cb=>handle_event: 
// AT+CMER=3,0,0,1
event_reporting(struct headset *hs, const char *buf)
	=>telephony_event_reporting_req(hs, ag.er_ind);
		=>telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
			=>hfp_slc_complete(hs);
				=>headset_set_state(hs, HEADSET_STATE_CONNECTED);
					//#define AUDIO_HEADSET_INTERFACE "org.bluez.Headset"
					=>g_dbus_emit_signal(hs->conn, hs->path,
												AUDIO_HEADSET_INTERFACE,"Connected",DBUS_TYPE_INVALID);
					=>g_dbus_emit_property_changed(hs->conn, hs->path,AUDIO_HEADSET_INTERFACE, "Connected");
					=>active_devices = g_slist_append(active_devices, hs);
					=>btd_service_connecting_complete(hs->service, 0); //
						=>change_state(service, BTD_SERVICE_STATE_CONNECTED, 0);
							=>service->state = state;
					=>hs->state = state;

bluetoothd:
int main(int argc, char *argv[])
{
	GOptionContext *context;
	GError *err = NULL;
	uint16_t sdp_mtu = 0;
	uint32_t sdp_flags = 0;
	int gdbus_flags = 0;
	guint signal, watchdog;
	const char *watchdog_usec;

	init_defaults();
	static void init_defaults(void)
	{
		uint8_t major, minor;

		/* Default HCId settings */
		memset(&main_opts, 0, sizeof(main_opts));
		main_opts.name = g_strdup_printf("BlueZ %s", VERSION); <tag1>
		main_opts.class = 0x000000;
		main_opts.pairto = DEFAULT_PAIRABLE_TIMEOUT; <tag2>
		main_opts.discovto = DEFAULT_DISCOVERABLE_TIMEOUT;
		main_opts.reverse_sdp = TRUE;
		main_opts.name_resolv = TRUE;
		main_opts.debug_keys = FALSE;

		if (sscanf(VERSION, "%hhu.%hhu", &major, &minor) != 2)
			return;

		main_opts.did_source = 0x0002;		/* USB */
		main_opts.did_vendor = 0x1d6b;		/* Linux Foundation */
		main_opts.did_product = 0x0246;		/* BlueZ */
		main_opts.did_version = (major << 8 | minor);
	}

	context = g_option_context_new(NULL);
	g_option_context_add_main_entries(context, options, NULL);

	if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
		if (err != NULL) {
			g_printerr("%s\n", err->message);
			g_error_free(err);
		} else
			g_printerr("An unknown error occurred\n");
		exit(1);
	}

	g_option_context_free(context);

	if (option_version == TRUE) {
		printf("%s\n", VERSION);
		exit(0);
	}

	umask(0077);

	btd_backtrace_init();

	event_loop = g_main_loop_new(NULL, FALSE);

	signal = setup_signalfd();
	static guint setup_signalfd(void)
	{
		GIOChannel *channel;
		guint source;
		sigset_t mask;
		int fd;

		sigemptyset(&mask);
		sigaddset(&mask, SIGINT);
		sigaddset(&mask, SIGTERM);
		sigaddset(&mask, SIGUSR2);

		if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
			perror("Failed to set signal mask");
			return 0;
		}

		fd = signalfd(-1, &mask, 0);
		if (fd < 0) {
			perror("Failed to create signal descriptor");
			return 0;
		}

		channel = g_io_channel_unix_new(fd);

		g_io_channel_set_close_on_unref(channel, TRUE);
		g_io_channel_set_encoding(channel, NULL, NULL);
		g_io_channel_set_buffered(channel, FALSE);

		source = g_io_add_watch(channel,
					G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
					signal_handler, NULL);

		g_io_channel_unref(channel);

		return source;
	}

	/* bluettothd -d 则将日志写入 log文件. 将print的输出重定向到log文件... */
	__btd_log_init(option_debug, option_detach);
	void __btd_log_init(const char *debug, int detach)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		int option = LOG_NDELAY | LOG_PID;

		if (debug != NULL)
			enabled = g_strsplit_set(debug, ":, ", 0);

		__btd_enable_debug(__start___debug, __stop___debug);

		init_log_file();
		static int init_log_file(void)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			int fd = -1;

			remove(LOG_FILE);
			fd = open(LOG_FILE, O_CREAT | O_RDWR | O_SYNC, 0666);
			if(fd >= 0) {
				dup2(fd, STDOUT_FILENO); /* 重定向终端输出 */
				dup2(fd, STDERR_FILENO);
				close(fd);
				fd = -1;
				return 0;
			}
			return -1;
		}
		logging_open();
		static void logging_open(void)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			struct sockaddr_hci addr;
			int fd;

			if (logging_fd >= 0)
				return;

			fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
			if (fd < 0)
				return;

			memset(&addr, 0, sizeof(addr));
			addr.hci_family = AF_BLUETOOTH;
			addr.hci_dev = HCI_DEV_NONE;
			addr.hci_channel = HCI_CHANNEL_LOGGING;

			if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
				close(fd);
				return;
			}

			logging_fd = fd;
		}

		if (!detach)
			option |= LOG_PERROR;

		openlog(LOG_IDENT, option, LOG_DAEMON);

		info("Bluetooth daemon %s", VERSION);
	}

	g_log_set_handler("GLib", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL |
							G_LOG_FLAG_RECURSION,
							log_handler, NULL);

	sd_notify(0, "STATUS=Starting up");

	if (option_configfile)
		main_conf_file_path = option_configfile;
	else
		main_conf_file_path = CONFIGDIR "/main.conf";
	#define CONFIGDIR "/etc/bluetooth"

	main_conf = load_config(main_conf_file_path);

	parse_config(main_conf);
	static void parse_config(GKeyFile *config)
	{
		GError *err = NULL;
		char *str;
		int val;
		gboolean boolean;

		if (!config)
			return;

		check_config(config);

		DBG("parsing %s", main_conf_file_path);

		val = g_key_file_get_integer(config, "General",
							"DiscoverableTimeout", &err);
		if (err) {
			DBG("%s", err->message);
			g_clear_error(&err);
		} else {
			DBG("discovto=%d", val);
			main_opts.discovto = val;
		}

		val = g_key_file_get_integer(config, "General",
							"PairableTimeout", &err);
		if (err) {
			DBG("%s", err->message);
			g_clear_error(&err);
		} else {
			DBG("pairto=%d", val);
			main_opts.pairto = val;
		}

		val = g_key_file_get_integer(config, "General", "AutoConnectTimeout",
										&err);
		if (err) {
			DBG("%s", err->message);
			g_clear_error(&err);
		} else {
			DBG("auto_to=%d", val);
			main_opts.autoto = val;
		}

		str = g_key_file_get_string(config, "General", "Privacy", &err); <tag3>
		if (err) {
			DBG("%s", err->message);
			g_clear_error(&err);
			main_opts.privacy = 0x00;
		} else {
			DBG("privacy=%s", str);

			if (!strcmp(str, "device"))
				main_opts.privacy = 0x01;
			else if (!strcmp(str, "off"))
				main_opts.privacy = 0x00;
			else {
				DBG("Invalid privacy option: %s", str);
				main_opts.privacy = 0x00;
			}

			g_free(str);
		}

		str = g_key_file_get_string(config, "General", "Name", &err);
		if (err) {
			DBG("%s", err->message);
			g_clear_error(&err);
		} else {
			DBG("name=%s", str);
			g_free(main_opts.name);
			main_opts.name = str;
		}

		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		str = g_key_file_get_string(config, "General", "Class", &err);
		if (err) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			DBG("%s", err->message);
			g_clear_error(&err);
		} else { //
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			DBG("class=%s", str);
			main_opts.class = strtol(str, NULL, 16);
			g_free(str);
		}

		str = g_key_file_get_string(config, "General", "DeviceID", &err);
		if (err) {
			DBG("%s", err->message);
			g_clear_error(&err);
		} else {
			DBG("deviceid=%s", str);
			parse_did(str);
			g_free(str);
		}

		boolean = g_key_file_get_boolean(config, "General",
							"ReverseServiceDiscovery", &err);
		if (err) {
			DBG("%s", err->message);
			g_clear_error(&err);
		} else
			main_opts.reverse_sdp = boolean;

		boolean = g_key_file_get_boolean(config, "General",
							"NameResolving", &err);
		if (err)
			g_clear_error(&err);
		else
			main_opts.name_resolv = boolean;

		boolean = g_key_file_get_boolean(config, "General",
							"DebugKeys", &err);
		if (err)
			g_clear_error(&err);
		else
			main_opts.debug_keys = boolean;

		str = g_key_file_get_string(config, "General", "ControllerMode", &err);
		if (err) {
			g_clear_error(&err);
		} else {
			DBG("ControllerMode=%s", str);
			main_opts.mode = get_mode(str);
			g_free(str);
		}

		str = g_key_file_get_string(config, "General", "MultiProfile", &err);
		if (err) {
			g_clear_error(&err);
		} else {
			DBG("MultiProfile=%s", str);

			if (!strcmp(str, "single"))
				mps = MPS_SINGLE;
			else if (!strcmp(str, "multiple"))
				mps = MPS_MULTIPLE;

			g_free(str);
		}

		boolean = g_key_file_get_boolean(config, "General",
							"FastConnectable", &err);
		if (err)
			g_clear_error(&err);
		else
			main_opts.fast_conn = boolean;

		str = g_key_file_get_string(config, "GATT", "Cache", &err);
		if (err) {
			g_clear_error(&err);
			main_opts.gatt_cache = BT_GATT_CACHE_ALWAYS;
			return;
		}

		main_opts.gatt_cache = parse_gatt_cache(str);

		g_free(str);
	}

	if (connect_dbus() < 0) {
		error("Unable to get on D-Bus");
		exit(1);
	}

	if (option_experimental)
		gdbus_flags = G_DBUS_FLAG_ENABLE_EXPERIMENTAL;

	g_dbus_set_flags(gdbus_flags);

	if (adapter_init() < 0) {
		error("Adapter handling initialization failed");
		exit(1);
	}
	int adapter_init(void)
	{
		dbus_conn = btd_get_dbus_connection(); <tag4>
		DBusConnection *btd_get_dbus_connection(void)
		{
			return connection;
		}

		mgmt_master = mgmt_new_default(); <tag5>
		if (!mgmt_master) {
			error("Failed to access management interface");
			return -EIO;
		}
		struct mgmt *mgmt_new_default(void)
		{
			struct mgmt *mgmt;
			union {
				struct sockaddr common;
				struct sockaddr_hci hci;
			} addr;
			int fd;

			fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
										BTPROTO_HCI);
			if (fd < 0)
				return NULL;

			memset(&addr, 0, sizeof(addr));
			addr.hci.hci_family = AF_BLUETOOTH;
			addr.hci.hci_dev = HCI_DEV_NONE;
			addr.hci.hci_channel = HCI_CHANNEL_CONTROL;

			if (bind(fd, &addr.common, sizeof(addr.hci)) < 0) {
				close(fd);
				return NULL;
			}

			mgmt = mgmt_new(fd);
			if (!mgmt) {
				close(fd);
				return NULL;
			}

			mgmt->close_on_unref = true;

			return mgmt;
		}

		if (getenv("MGMT_DEBUG"))
			mgmt_set_debug(mgmt_master, mgmt_debug, "mgmt: ", NULL);

		DBG("sending read version command");

		if (mgmt_send(mgmt_master, MGMT_OP_READ_VERSION,
					MGMT_INDEX_NONE, 0, NULL,
					read_version_complete, NULL, NULL) > 0)
			return 0;

		error("Failed to read management version information");

		return -EIO;
	}

	btd_device_init();
	void btd_device_init(void)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		dbus_conn = btd_get_dbus_connection();
		service_state_cb_id = btd_service_add_state_cb(
							service_state_changed, NULL);
	}
	btd_agent_init();
	void btd_agent_init(void)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		agent_list = g_hash_table_new_full(g_str_hash, g_str_equal,
							NULL, agent_destroy);

		DBG("");
		default_agents = queue_new();

		g_dbus_register_interface(btd_get_dbus_connection(),
					"/org/bluez", "org.bluez.AgentManager1",
					methods, NULL, NULL, NULL, NULL);
	}
	btd_profile_init();
	void btd_profile_init(void)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		g_dbus_register_interface(btd_get_dbus_connection(),
					"/org/bluez", "org.bluez.ProfileManager1",
					methods, NULL, NULL, NULL, NULL);
	}

	if (main_opts.mode != BT_MODE_LE) {
		if (option_compat == TRUE)  //GM: no into
			sdp_flags |= SDP_SERVER_COMPAT;

		start_sdp_server(sdp_mtu, sdp_flags);
		int start_sdp_server(uint16_t mtu, uint32_t flags)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			int compat = flags & SDP_SERVER_COMPAT;
			int master = flags & SDP_SERVER_MASTER;
			GIOChannel *io;

			info("Starting SDP server");

			if (init_server(mtu, master, compat) < 0) {
				error("Server initialization failed");
				return -1;
			}
			static int init_server(uint16_t mtu, int master, int compat)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct l2cap_options opts;
				struct sockaddr_l2 l2addr;
				struct sockaddr_un unaddr;
				socklen_t optlen;

				/* Register the public browse group root */
				register_public_browse_group();
				void register_public_browse_group(void)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					sdp_list_t *browselist;
					uuid_t bgscid, pbgid;
					sdp_data_t *sdpdata;
					sdp_record_t *browse = sdp_record_alloc();
					sdp_record_t *sdp_record_alloc(void)
					{
						sdp_record_t *rec = malloc(sizeof(sdp_record_t));

						if (!rec)
							return NULL;

						memset(rec, 0, sizeof(sdp_record_t));
						rec->handle = 0xffffffff;
						return rec;
					}

					browse->handle = SDP_SERVER_RECORD_HANDLE + 1;

					sdp_record_add(BDADDR_ANY, browse);
					void sdp_record_add(const bdaddr_t *device, sdp_record_t *rec)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						sdp_access_t *dev;

						SDPDBG("Adding rec : 0x%lx", (long) rec);
						SDPDBG("with handle : 0x%x", rec->handle);

						service_db = sdp_list_insert_sorted(service_db, rec, record_sort);

						dev = malloc(sizeof(*dev));
						if (!dev)
							return;

						bacpy(&dev->device, device);
						dev->handle = rec->handle;

						access_db = sdp_list_insert_sorted(access_db, dev, access_sort);
					}
					sdpdata = sdp_data_alloc(SDP_UINT32, &browse->handle);
					sdp_attr_add(browse, SDP_ATTR_RECORD_HANDLE, sdpdata);

					sdp_uuid16_create(&bgscid, BROWSE_GRP_DESC_SVCLASS_ID);
					browselist = sdp_list_append(0, &bgscid);
					sdp_set_service_classes(browse, browselist);
					static inline int sdp_set_service_classes(sdp_record_t *rec, sdp_list_t *seq)
					{
						return sdp_set_uuidseq_attr(rec, SDP_ATTR_SVCLASS_ID_LIST, seq);
						#define SDP_ATTR_SVCLASS_ID_LIST		0x0001
					}
					sdp_list_free(browselist, 0);

					sdp_uuid16_create(&pbgid, PUBLIC_BROWSE_GROUP);
					sdp_attr_add_new(browse, SDP_ATTR_GROUP_ID,
								SDP_UUID16, &pbgid.value.uuid16);
				}

				/* Register the SDP server's service record */
				register_server_service();
				void register_server_service(void)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					sdp_list_t *classIDList;
					uuid_t classID;
					void **versions, **versionDTDs;
					uint8_t dtd;
					sdp_data_t *pData;
					int i;

					server = sdp_record_alloc();
					server->pattern = NULL;

					/* Force the record to be SDP_SERVER_RECORD_HANDLE */
					server->handle = SDP_SERVER_RECORD_HANDLE;

					sdp_record_add(BDADDR_ANY, server);
					sdp_attr_add(server, SDP_ATTR_RECORD_HANDLE,
								sdp_data_alloc(SDP_UINT32, &server->handle));

					sdp_uuid16_create(&classID, SDP_SERVER_SVCLASS_ID);
					classIDList = sdp_list_append(0, &classID);
					sdp_set_service_classes(server, classIDList);
					sdp_list_free(classIDList, 0);

					/*
					 * Set the version numbers supported, these are passed as arguments
					 * to the server on command line. Now defaults to 1.0
					 * Build the version number sequence first
					 */
					versions = malloc(sdpServerVnumEntries * sizeof(void *));
					versionDTDs = malloc(sdpServerVnumEntries * sizeof(void *));
					dtd = SDP_UINT16;
					for (i = 0; i < sdpServerVnumEntries; i++) {
						uint16_t *version = malloc(sizeof(uint16_t));
						*version = sdpVnumArray[i].major;
						*version = (*version << 8);
						*version |= sdpVnumArray[i].minor;
						versions[i] = version;
						versionDTDs[i] = &dtd;
					}
					pData = sdp_seq_alloc(versionDTDs, versions, sdpServerVnumEntries);
					for (i = 0; i < sdpServerVnumEntries; i++)
						free(versions[i]);
					free(versions);
					free(versionDTDs);
					sdp_attr_add(server, SDP_ATTR_VERSION_NUM_LIST, pData);

					update_db_timestamp();
				}

				/* Create L2CAP socket */
				l2cap_sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
				if (l2cap_sock < 0) {
					error("opening L2CAP socket: %s", strerror(errno));
					return -1;
				}

				memset(&l2addr, 0, sizeof(l2addr));
				l2addr.l2_family = AF_BLUETOOTH;
				bacpy(&l2addr.l2_bdaddr, BDADDR_ANY);
				l2addr.l2_psm = htobs(SDP_PSM);

				if (bind(l2cap_sock, (struct sockaddr *) &l2addr, sizeof(l2addr)) < 0) {
					error("binding L2CAP socket: %s", strerror(errno));
					return -1;
				}

				if (master) {
					int opt = L2CAP_LM_MASTER;
					if (setsockopt(l2cap_sock, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0) {
						error("setsockopt: %s", strerror(errno));
						return -1;
					}
				}

				if (mtu > 0) {
					memset(&opts, 0, sizeof(opts));
					optlen = sizeof(opts);

					if (getsockopt(l2cap_sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen) < 0) {
						error("getsockopt: %s", strerror(errno));
						return -1;
					}

					opts.omtu = mtu;
					opts.imtu = mtu;

					if (setsockopt(l2cap_sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) {
						error("setsockopt: %s", strerror(errno));
						return -1;
					}
				}

				if (listen(l2cap_sock, 5) < 0) {
					error("listen: %s", strerror(errno));
					return -1;
				}

				if (!compat) {
					unix_sock = -1;
					return 0;
				}

				/* Create local Unix socket */
				unix_sock = socket(PF_UNIX, SOCK_STREAM, 0);
				if (unix_sock < 0) {
					error("opening UNIX socket: %s", strerror(errno));
					return -1;
				}

				memset(&unaddr, 0, sizeof(unaddr));
				unaddr.sun_family = AF_UNIX;
				strcpy(unaddr.sun_path, SDP_UNIX_PATH);

				unlink(unaddr.sun_path);

				if (bind(unix_sock, (struct sockaddr *) &unaddr, sizeof(unaddr)) < 0) {
					error("binding UNIX socket: %s", strerror(errno));
					return -1;
				}

				if (listen(unix_sock, 5) < 0) {
					error("listen UNIX socket: %s", strerror(errno));
					return -1;
				}

				chmod(SDP_UNIX_PATH, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
				#define SDP_UNIX_PATH "/var/run/sdp"

				return 0;
			}

			io = g_io_channel_unix_new(l2cap_sock);
			g_io_channel_set_close_on_unref(io, TRUE);

			l2cap_id = g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
							io_accept_event, &l2cap_sock);
			g_io_channel_unref(io);

			if (compat && unix_sock > fileno(stderr)) {
				io = g_io_channel_unix_new(unix_sock);
				g_io_channel_set_close_on_unref(io, TRUE);

				unix_id = g_io_add_watch(io,
							G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
							io_accept_event, &unix_sock);
				g_io_channel_unref(io);
			}

			return 0;
		}

		if (main_opts.did_source > 0) // GM: into
			register_device_id(main_opts.did_source,
						main_opts.did_vendor,
						main_opts.did_product,
						main_opts.did_version);
			void register_device_id(uint16_t source, uint16_t vendor,
								uint16_t product, uint16_t version)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				const uint16_t spec = 0x0103;
				const uint8_t primary = 1;
				sdp_list_t *class_list, *group_list, *profile_list;
				uuid_t class_uuid, group_uuid;
				sdp_data_t *sdp_data, *primary_data, *source_data;
				sdp_data_t *spec_data, *vendor_data, *product_data, *version_data;
				sdp_profile_desc_t profile;
				sdp_record_t *record = sdp_record_alloc();

				DBG("Adding device id record for %04x:%04x:%04x:%04x",
								source, vendor, product, version);

				record->handle = sdp_next_handle();

				sdp_record_add(BDADDR_ANY, record);
				sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle);
				sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data);

				sdp_uuid16_create(&class_uuid, PNP_INFO_SVCLASS_ID);
				class_list = sdp_list_append(0, &class_uuid);
				sdp_set_service_classes(record, class_list);
				sdp_list_free(class_list, NULL);

				sdp_uuid16_create(&group_uuid, PUBLIC_BROWSE_GROUP);
				group_list = sdp_list_append(NULL, &group_uuid);
				sdp_set_browse_groups(record, group_list);
				sdp_list_free(group_list, NULL);

				sdp_uuid16_create(&profile.uuid, PNP_INFO_PROFILE_ID);
				profile.version = spec;
				profile_list = sdp_list_append(NULL, &profile);
				sdp_set_profile_descs(record, profile_list);
				sdp_list_free(profile_list, NULL);

				spec_data = sdp_data_alloc(SDP_UINT16, &spec);
				sdp_attr_add(record, 0x0200, spec_data);

				vendor_data = sdp_data_alloc(SDP_UINT16, &vendor);
				sdp_attr_add(record, 0x0201, vendor_data);

				product_data = sdp_data_alloc(SDP_UINT16, &product);
				sdp_attr_add(record, 0x0202, product_data);

				version_data = sdp_data_alloc(SDP_UINT16, &version);
				sdp_attr_add(record, 0x0203, version_data);

				primary_data = sdp_data_alloc(SDP_BOOL, &primary);
				sdp_attr_add(record, 0x0204, primary_data);

				source_data = sdp_data_alloc(SDP_UINT16, &source);
				sdp_attr_add(record, 0x0205, source_data);

				update_db_timestamp();
			}
	}

	if (mps != MPS_OFF) //GM : no
		register_mps(mps == MPS_MULTIPLE);

	/* Loading plugins has to be done after D-Bus has been setup since
	 * the plugins might wanna expose some paths on the bus. However the
	 * best order of how to init various subsystems of the Bluetooth
	 * daemon needs to be re-worked. */
	/* 可以通过bluetoothd --plugin 或 -p 指定要enbale 的plugin.
	 * 可以通过bluetoothd --noplugin 或 -P 指定要disabale 的plugin.
	 * 若没有指定, 则option_plugin and option_noplugin == NULL
	 */
	plugin_init(option_plugin, option_noplugin);
	gboolean plugin_init(const char *enable, const char *disable)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		GSList *list;
		GDir *dir;
		const char *file;
		char **cli_disabled, **cli_enabled;
		unsigned int i;

		/* Make a call to BtIO API so its symbols got resolved before the
		 * plugins are loaded. */
		bt_io_error_quark();

		if (enable)
			cli_enabled = g_strsplit_set(enable, ", ", -1);
		else
			cli_enabled = NULL;

		if (disable)
			cli_disabled = g_strsplit_set(disable, ", ", -1);
		else
			cli_disabled = NULL;

		DBG("Loading builtin plugins");

		#define BLUETOOTH_PLUGIN_DEFINE(name, version, priority, init, exit) \
			struct bluetooth_plugin_desc __bluetooth_builtin_ ## name = { \
							#name, version, priority, init, exit \
						};

		static struct bluetooth_plugin_desc *__bluetooth_builtin[] = {
		  &__bluetooth_builtin_hostname,
		  &__bluetooth_builtin_wiimote,
		  &__bluetooth_builtin_autopair,
		  &__bluetooth_builtin_policy,
		  &__bluetooth_builtin_uni_audioplugin,
		  &__bluetooth_builtin_a2dp,
		  &__bluetooth_builtin_avrcp,
		  &__bluetooth_builtin_network,
		  &__bluetooth_builtin_input,
		  &__bluetooth_builtin_hog,
		  &__bluetooth_builtin_gap,
		  &__bluetooth_builtin_scanparam,
		  &__bluetooth_builtin_deviceinfo,
		  NULL
		};
		TH_PLUGIN_DEFINE(hostname, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
										hostname_init, hostname_exit)
		for (i = 0; __bluetooth_builtin[i]; i++) {
			if (!enable_plugin(__bluetooth_builtin[i]->name, cli_enabled, cli_disabled))
				continue;
			static gboolean enable_plugin(const char *name, char **cli_enable,
										char **cli_disable)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				if (cli_disable) {
					for (; *cli_disable; cli_disable++)
						if (g_pattern_match_simple(*cli_disable, name))
							break;
					if (*cli_disable) {
						info("Excluding (cli) %s", name);
						return FALSE;
					}
				}

				if (cli_enable) {
					for (; *cli_enable; cli_enable++)
						if (g_pattern_match_simple(*cli_enable, name))
							break;
					if (!*cli_enable) {
						info("Ignoring (cli) %s", name);
						return FALSE;
					}
				}

				/* cli_disable and cli_enable 都为 NULL, 即不配置就都enable */
				return TRUE;
			}

			add_plugin(NULL,  __bluetooth_builtin[i]);
			static gboolean add_plugin(void *handle, struct bluetooth_plugin_desc *desc)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct bluetooth_plugin *plugin;

				if (desc->init == NULL)
					return FALSE;

				if (g_str_equal(desc->version, VERSION) == FALSE) {
					error("Version mismatch for %s", desc->name);
					return FALSE;
				}

				DBG("Loading %s plugin", desc->name);

				plugin = g_try_new0(struct bluetooth_plugin, 1);
				if (plugin == NULL)
					return FALSE;

				plugin->handle = handle;
				plugin->active = FALSE;
				plugin->desc = desc;

				__btd_enable_debug(desc->debug_start, desc->debug_stop);

				/* 按优先级加入队列 */
				plugins = g_slist_insert_sorted(plugins, plugin, compare_priority); <tag6>
				static int compare_priority(gconstpointer a, gconstpointer b)
				{
					const struct bluetooth_plugin *plugin1 = a;
					const struct bluetooth_plugin *plugin2 = b;

					return plugin2->desc->priority - plugin1->desc->priority;
				}

				return TRUE;
			}
		}

		if (strlen(PLUGINDIR) == 0)
			goto start;

		//Loading plugins /home/work/kuuga/project/linux_learn_project/br03_bt2/bluetooth/build/lib/bluetooth/plugins
		DBG("Loading plugins %s", PLUGINDIR);

		dir = g_dir_open(PLUGINDIR, 0, NULL);
		if (!dir)
			goto start;

		/* 刚刚是加载内建的plugin, 现在是动态加载libxx.so的plugin */
		while ((file = g_dir_read_name(dir)) != NULL) {
			struct bluetooth_plugin_desc *desc;
			void *handle;
			char *filename;

			if (g_str_has_prefix(file, "lib") == TRUE ||
					g_str_has_suffix(file, ".so") == FALSE)
				continue;

			filename = g_build_filename(PLUGINDIR, file, NULL);

			handle = dlopen(filename, RTLD_NOW);
			if (handle == NULL) {
				error("Can't load plugin %s: %s", filename,
									dlerror());
				g_free(filename);
				continue;
			}

			g_free(filename);

			desc = dlsym(handle, "bluetooth_plugin_desc");
			if (desc == NULL) {
				error("Can't load plugin description: %s", dlerror());
				dlclose(handle);
				continue;
			}

			if (!enable_plugin(desc->name, cli_enabled, cli_disabled)) {
				dlclose(handle);
				continue;
			}

			if (add_plugin(handle, desc) == FALSE)
				dlclose(handle);
		}

		g_dir_close(dir);

	start:
		/* 对所有plugin执行其init()函数. */
		for (list = plugins; list; list = list->next) {
			struct bluetooth_plugin *plugin = list->data;
			int err;

			err = plugin->desc->init();
			if (err < 0) {
				if (err == -ENOSYS)
					warn("System does not support %s plugin",
								plugin->desc->name);
				else
					error("Failed to init %s plugin",
								plugin->desc->name);
				continue;
			}

			plugin->active = TRUE;
		}

		g_strfreev(cli_enabled);
		g_strfreev(cli_disabled);

		return TRUE;
	}

	/* no need to keep parsed option in memory */
	free_options();

	rfkill_init();
	void rfkill_init(void)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		int fd;
		GIOChannel *channel;

		fd = open("/dev/rfkill", O_RDWR);
		if (fd < 0) {
			error("Failed to open RFKILL control device");
			return;
		}

		channel = g_io_channel_unix_new(fd);
		g_io_channel_set_close_on_unref(channel, TRUE);

		watch = g_io_add_watch(channel,
					G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
					rfkill_event, NULL);

		g_io_channel_unref(channel);
	}

	DBG("Entering main loop");

	sd_notify(0, "STATUS=Running");
	sd_notify(0, "READY=1");

	watchdog_usec = getenv("WATCHDOG_USEC");
	if (watchdog_usec) {
		unsigned int seconds;

		seconds = atoi(watchdog_usec) / (1000 * 1000);
		info("Watchdog timeout is %d seconds", seconds);

		watchdog = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
							seconds / 2,
							watchdog_callback,
							NULL, NULL);
	} else //GM here
		watchdog = 0;

	g_main_loop_run(event_loop); // while

	sd_notify(0, "STATUS=Quitting");

	g_source_remove(signal);

	plugin_cleanup();

	btd_profile_cleanup();
	btd_agent_cleanup();
	btd_device_cleanup();

	adapter_cleanup();

	rfkill_exit();

	if (main_opts.mode != BT_MODE_LE)
		stop_sdp_server();

	g_main_loop_unref(event_loop);

	if (main_conf)
		g_key_file_free(main_conf);

	disconnect_dbus();

	info("Exit");

	if (watchdog > 0)
		g_source_remove(watchdog);

	__btd_log_cleanup();

	return 0;
}

static void read_version_complete(uint8_t status, uint16_t length,
						const void *param, void *user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	const struct mgmt_rp_read_version *rp = param;

	if (status != MGMT_STATUS_SUCCESS) {
		error("Failed to read version information: %s (0x%02x)",
						mgmt_errstr(status), status);
		return;
	}

	if (length < sizeof(*rp)) {
		error("Wrong size of read version response");
		return;
	}

	mgmt_version = rp->version;
	mgmt_revision = btohs(rp->revision);

	info("Bluetooth management interface %u.%u initialized",
						mgmt_version, mgmt_revision);

	if (mgmt_version < 1) {
		error("Version 1.0 or later of management interface required");
		abort();
	}

	DBG("sending read supported commands command");

	/*
	 * It is irrelevant if this command succeeds or fails. In case of
	 * failure safe settings are assumed.
	 */
	mgmt_send(mgmt_master, MGMT_OP_READ_COMMANDS,
				MGMT_INDEX_NONE, 0, NULL,
				read_commands_complete, NULL, NULL);
	static void read_commands_complete(uint8_t status, uint16_t length,
						const void *param, void *user_data)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		const struct mgmt_rp_read_commands *rp = param;
		uint16_t num_commands, num_events;
		const uint16_t *opcode;
		size_t expected_len;
		int i;

		if (status != MGMT_STATUS_SUCCESS) {
			error("Failed to read supported commands: %s (0x%02x)",
							mgmt_errstr(status), status);
			return;
		}

		if (length < sizeof(*rp)) {
			error("Wrong size of read commands response");
			return;
		}

		num_commands = btohs(rp->num_commands);
		num_events = btohs(rp->num_events);

		DBG("Number of commands: %d", num_commands);
		DBG("Number of events: %d", num_events);

		expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) +
							num_events * sizeof(uint16_t);

		if (length < expected_len) {
			error("Too small reply for supported commands: (%u != %zu)",
								length, expected_len);
			return;
		}

		opcode = rp->opcodes;

		for (i = 0; i < num_commands; i++) {
			uint16_t op = get_le16(opcode++);

			if (op == MGMT_OP_ADD_DEVICE) {
				DBG("enabling kernel-side connection control");
				kernel_conn_control = true;
			}
		}
	}

	mgmt_register(mgmt_master, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
						index_added, NULL, NULL);
	static void index_added(uint16_t index, uint16_t length, const void *param,
								void *user_data)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct btd_adapter *adapter;

		DBG("index %u", index);

		adapter = btd_adapter_lookup(index);
		if (adapter) {
			btd_warn(adapter->dev_id,
				"Ignoring index added for an already existing adapter");
			return;
		}
		static struct btd_adapter *btd_adapter_lookup(uint16_t index)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			GList *list;

			for (list = g_list_first(adapter_list); list;
								list = g_list_next(list)) {
				struct btd_adapter *adapter = list->data;

				if (adapter->dev_id == index)
					return adapter;
			}

			return NULL;
		}

		adapter = btd_adapter_new(index);
		if (!adapter) {
			btd_error(index,
				"Unable to create new adapter for index %u", index);
			return;
		}
		static struct btd_adapter *btd_adapter_new(uint16_t index)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			struct btd_adapter *adapter;

			adapter = g_try_new0(struct btd_adapter, 1); <tag8>
			if (!adapter)
				return NULL;

			adapter->dev_id = index; <tag9>
			adapter->mgmt = mgmt_ref(mgmt_master);
			adapter->pincode_requested = false;

			/*
			 * Setup default configuration values. These are either adapter
			 * defaults or from a system wide configuration file.
			 *
			 * Some value might be overwritten later on by adapter specific
			 * configuration. This is to make sure that sane defaults are
			 * always present.
			 */
			adapter->system_name = g_strdup(main_opts.name); <tag12>
			adapter->major_class = (main_opts.class & 0x001f00) >> 8;
			adapter->minor_class = (main_opts.class & 0x0000fc) >> 2;
			adapter->modalias = bt_modalias(main_opts.did_source,
								main_opts.did_vendor,
								main_opts.did_product,
								main_opts.did_version);
			adapter->discoverable_timeout = main_opts.discovto;
			adapter->pairable_timeout = main_opts.pairto;

			DBG("System name: %s", adapter->system_name);
			DBG("Major class: %u", adapter->major_class);
			DBG("Minor class: %u", adapter->minor_class);
			DBG("Modalias: %s", adapter->modalias);
			DBG("Discoverable timeout: %u seconds", adapter->discoverable_timeout);
			DBG("Pairable timeout: %u seconds", adapter->pairable_timeout);
#if 0
			src/adapter.c:btd_adapter_new(5582) System name: BlueZ 5.47
			src/adapter.c:btd_adapter_new(5583) Major class: 1
			src/adapter.c:btd_adapter_new(5584) Minor class: 0
			src/adapter.c:btd_adapter_new(5585) Modalias: usb:v1D6Bp0246d052F
			src/adapter.c:btd_adapter_new(5586) Discoverable timeout: 180 seconds
			src/adapter.c:btd_adapter_new(5587) Pairable timeout: 0 seconds
#endif

			adapter->auths = g_queue_new(); <tag10>

			return btd_adapter_ref(adapter);
			struct btd_adapter *btd_adapter_ref(struct btd_adapter *adapter)
			{
				__sync_fetch_and_add(&adapter->ref_count, 1);

				return adapter;
			}
		}

		/*
		 * Protect against potential two executions of read controller info.
		 *
		 * In case the start of the daemon and the action of adding a new
		 * controller coincide this function might be called twice.
		 *
		 * To avoid the double execution of reading the controller info,
		 * add the adapter already to the list. If an adapter is already
		 * present, the second notification will cause a warning. If the
		 * command fails the adapter is removed from the list again.
		 */
		adapter_list = g_list_append(adapter_list, adapter); <tag7>

		DBG("sending read info command for index %u", index);

		if (mgmt_send(mgmt_master, MGMT_OP_READ_INFO, index, 0, NULL,
						read_info_complete, adapter, NULL) > 0)
			return;
		static void read_info_complete(uint8_t status, uint16_t length,
							const void *param, void *user_data)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			struct btd_adapter *adapter = user_data;
			const struct mgmt_rp_read_info *rp = param;
			uint32_t missing_settings;
			int err;

			DBG("index %u status 0x%02x", adapter->dev_id, status);
			//src/adapter.c:read_info_complete(8417) index 0 status 0x00

			if (status != MGMT_STATUS_SUCCESS) {
				btd_error(adapter->dev_id,
						"Failed to read info for index %u: %s (0x%02x)",
						adapter->dev_id, mgmt_errstr(status), status);
				goto failed;
			}

			if (length < sizeof(*rp)) {
				btd_error(adapter->dev_id,
						"Too small read info complete response");
				goto failed;
			}

			/*
			 * Store controller information for class of device, device
			 * name, short name and settings.
			 *
			 * During the lifetime of the controller these will be updated by
			 * events and the information is required to keep the current
			 * state of the controller.
			 */
			adapter->dev_class = rp->dev_class[0] | (rp->dev_class[1] << 8) |
								(rp->dev_class[2] << 16); <tag11>
			adapter->name = g_strdup((const char *) rp->name); <tag11>
			adapter->short_name = g_strdup((const char *) rp->short_name);

			adapter->manufacturer = btohs(rp->manufacturer);

			adapter->supported_settings = btohl(rp->supported_settings);
			adapter->current_settings = btohl(rp->current_settings);

			clear_uuids(adapter);
			static int clear_uuids(struct btd_adapter *adapter)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct mgmt_cp_remove_uuid cp;

				memset(&cp, 0, sizeof(cp));

				DBG("sending clear uuids command for index %u", adapter->dev_id);

				if (mgmt_send(adapter->mgmt, MGMT_OP_REMOVE_UUID,
							adapter->dev_id, sizeof(cp), &cp,
							clear_uuids_complete, adapter, NULL) > 0)
					return 0;
				static void clear_uuids_complete(uint8_t status, uint16_t length,
									const void *param, void *user_data)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct btd_adapter *adapter = user_data;

					if (status != MGMT_STATUS_SUCCESS) {
						btd_error(adapter->dev_id, "Failed to clear UUIDs: %s (0x%02x)",
										mgmt_errstr(status), status);
						return;
					}

					/*
					 * The parameters are identical and also the task that is
					 * required in both cases. So it is safe to just call the
					 * event handling functions here.
					 */
					dev_class_changed_callback(adapter->dev_id, length, param, adapter);
					static void dev_class_changed_callback(uint16_t index, uint16_t length,
										const void *param, void *user_data)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						struct btd_adapter *adapter = user_data;
						const struct mgmt_cod *rp = param;
						uint32_t dev_class;

						if (length < sizeof(*rp)) {
							btd_error(adapter->dev_id,
								"Wrong size of class of device changed parameters");
							return;
						}

						dev_class = rp->val[0] | (rp->val[1] << 8) | (rp->val[2] << 16);

						if (dev_class == adapter->dev_class)
							return;

						DBG("Class: 0x%06x", dev_class);
						//src/adapter.c:dev_class_changed_callback(339) Class: 0x400100

						adapter->dev_class = dev_class;

						g_dbus_emit_property_changed(dbus_conn, adapter->path,
											ADAPTER_INTERFACE, "Class");
						#define ADAPTER_INTERFACE	"org.bluez.Adapter1"
					}
				}

				btd_error(adapter->dev_id, "Failed to clear UUIDs for index %u",
										adapter->dev_id);

				return -EIO;
			}
			clear_devices(adapter);
			static int clear_devices(struct btd_adapter *adapter)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct mgmt_cp_remove_device cp;

				if (!kernel_conn_control)
					return 0;

				memset(&cp, 0, sizeof(cp));

				DBG("sending clear devices command for index %u", adapter->dev_id);
				src/adapter.c:clear_devices(8288) sending clear devices command for index 0

				if (mgmt_send(adapter->mgmt, MGMT_OP_REMOVE_DEVICE,
							adapter->dev_id, sizeof(cp), &cp,
							clear_devices_complete, adapter, NULL) > 0)
					return 0;
				static void clear_devices_complete(uint8_t status, uint16_t length,
									const void *param, void *user_data)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					if (status != MGMT_STATUS_SUCCESS) {
						error("Failed to clear devices: %s (0x%02x)",
										mgmt_errstr(status), status);
						return;
					}
				}

				btd_error(adapter->dev_id, "Failed to clear devices for index %u",
										adapter->dev_id);

				return -EIO;
			}

			if (bacmp(&rp->bdaddr, BDADDR_ANY) == 0) {
				if (!set_static_addr(adapter)) {
					btd_error(adapter->dev_id,
							"No Bluetooth address for index %u",
							adapter->dev_id);
					goto failed;
				}
			} else {
				bacpy(&adapter->bdaddr, &rp->bdaddr); <tag13>
				if (!(adapter->supported_settings & MGMT_SETTING_LE))
					adapter->bdaddr_type = BDADDR_BREDR; <tag14>
				else
					adapter->bdaddr_type = BDADDR_LE_PUBLIC;
			}

			missing_settings = adapter->current_settings ^
								adapter->supported_settings;

			switch (main_opts.mode) {
			case BT_MODE_DUAL: //GM into here
				if (missing_settings & MGMT_SETTING_SSP)
					set_mode(adapter, MGMT_OP_SET_SSP, 0x01);
				if (missing_settings & MGMT_SETTING_LE)
					set_mode(adapter, MGMT_OP_SET_LE, 0x01);
				if (missing_settings & MGMT_SETTING_BREDR)
					set_mode(adapter, MGMT_OP_SET_BREDR, 0x01);
				break;
				static bool set_mode(struct btd_adapter *adapter, uint16_t opcode,
											uint8_t mode)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct mgmt_mode cp;

					memset(&cp, 0, sizeof(cp));
					cp.val = mode;

					DBG("sending set mode command for index %u", adapter->dev_id);

					if (mgmt_send(adapter->mgmt, opcode,
								adapter->dev_id, sizeof(cp), &cp,
								set_mode_complete, adapter, NULL) > 0)
						return true;
						static void set_mode_complete(uint8_t status, uint16_t length,
											const void *param, void *user_data)
						{
							printf("jokerb %s:in %d.\n",__func__,__LINE__);
							struct btd_adapter *adapter = user_data;

							if (status != MGMT_STATUS_SUCCESS) {
								btd_error(adapter->dev_id, "Failed to set mode: %s (0x%02x)",
												mgmt_errstr(status), status);
								return;
							}

							/*
							 * The parameters are identical and also the task that is
							 * required in both cases. So it is safe to just call the
							 * event handling functions here.
							 */
							new_settings_callback(adapter->dev_id, length, param, adapter);
							static void new_settings_callback(uint16_t index, uint16_t length,
												const void *param, void *user_data)
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								struct btd_adapter *adapter = user_data;
								uint32_t settings;

								if (length < sizeof(settings)) {
									btd_error(adapter->dev_id,
											"Wrong size of new settings parameters");
									return;
								}

								settings = get_le32(param);

								if (settings == adapter->current_settings)
									return;

								DBG("Settings: 0x%08x", settings);

								settings_changed(adapter, settings);
							}
						}

					btd_error(adapter->dev_id, "Failed to set mode for index %u",
											adapter->dev_id);

					return false;
				}
			case BT_MODE_BREDR:
				if (!(adapter->supported_settings & MGMT_SETTING_BREDR)) {
					btd_error(adapter->dev_id,
						"Ignoring adapter withouth BR/EDR support");
					goto failed;
				}

				if (missing_settings & MGMT_SETTING_SSP)
					set_mode(adapter, MGMT_OP_SET_SSP, 0x01);
				if (missing_settings & MGMT_SETTING_BREDR)
					set_mode(adapter, MGMT_OP_SET_BREDR, 0x01);
				if (adapter->current_settings & MGMT_SETTING_LE)
					set_mode(adapter, MGMT_OP_SET_LE, 0x00);
				break;
			case BT_MODE_LE:
				if (!(adapter->supported_settings & MGMT_SETTING_LE)) {
					btd_error(adapter->dev_id,
						"Ignoring adapter withouth LE support");
					goto failed;
				}

				if (missing_settings & MGMT_SETTING_LE)
					set_mode(adapter, MGMT_OP_SET_LE, 0x01);
				if (adapter->current_settings & MGMT_SETTING_BREDR)
					set_mode(adapter, MGMT_OP_SET_BREDR, 0x00);
				break;
			}

			if (missing_settings & MGMT_SETTING_SECURE_CONN)
				set_mode(adapter, MGMT_OP_SET_SECURE_CONN, 0x01);

			if (adapter->supported_settings & MGMT_SETTING_PRIVACY)
				set_privacy(adapter, main_opts.privacy);
				static int set_privacy(struct btd_adapter *adapter, uint8_t privacy)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct mgmt_cp_set_privacy cp;

					memset(&cp, 0, sizeof(cp));

					if (privacy) {
						uint8_t irk[16];

						if (load_irk(adapter, irk) == 0) {
							cp.privacy = privacy;
							memcpy(cp.irk, irk, 16);
						}
					}

					DBG("sending set privacy command for index %u", adapter->dev_id);
					DBG("setting privacy mode 0x%02x for index %u", cp.privacy,
											adapter->dev_id);
				//src/adapter.c:set_privacy(3439) sending set privacy command for index 0
				//src/adapter.c:set_privacy(3441) setting privacy mode 0x00 for index 0

					if (mgmt_send(adapter->mgmt, MGMT_OP_SET_PRIVACY,
								adapter->dev_id, sizeof(cp), &cp,
								set_privacy_complete, adapter, NULL) > 0)
						return 0;
					static void set_privacy_complete(uint8_t status, uint16_t length,
										const void *param, void *user_data)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						struct btd_adapter *adapter = user_data;

						if (status != MGMT_STATUS_SUCCESS) {
							btd_error(adapter->dev_id, "Failed to set privacy: %s (0x%02x)",
											mgmt_errstr(status), status);
							return;
						}

						DBG("Successfuly set privacy for index %u", adapter->dev_id);
					}

					btd_error(adapter->dev_id, "Failed to set privacy for index %u",
											adapter->dev_id);

					return -1;
				}

			if (main_opts.fast_conn &&
					(missing_settings & MGMT_SETTING_FAST_CONNECTABLE))
				set_mode(adapter, MGMT_OP_SET_FAST_CONNECTABLE, 0x01);

			err = adapter_register(adapter);
			if (err < 0) {
				btd_error(adapter->dev_id, "Unable to register new adapter");
				goto failed;
			}
			static int adapter_register(struct btd_adapter *adapter)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct agent *agent;
				struct gatt_db *db;

				if (powering_down)
					return -EBUSY;

				adapter->path = g_strdup_printf("/org/bluez/hci%d", adapter->dev_id);

				if (!g_dbus_register_interface(dbus_conn,
								adapter->path, ADAPTER_INTERFACE,
								adapter_methods, NULL,
								adapter_properties, adapter,
								adapter_free)) {
					btd_error(adapter->dev_id,
							"Adapter interface init failed on path %s",
										adapter->path);
					g_free(adapter->path);
					adapter->path = NULL;
					return -EINVAL;
				}

				if (adapters == NULL)
					adapter->is_default = true;

				adapters = g_slist_append(adapters, adapter); <tag15>

				agent = agent_get(NULL);
				if (agent) {
					uint8_t io_cap = agent_get_io_capability(agent);
					adapter_set_io_capability(adapter, io_cap);
					agent_unref(agent);
				}
				struct agent *agent_get(const char *owner)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct agent *agent;

					if (owner) {
						agent = g_hash_table_lookup(agent_list, owner);
						if (agent)
							return agent_ref(agent);
					}

					if (!queue_isempty(default_agents))
						return agent_ref(queue_peek_head(default_agents));

					return NULL;
				}

#if 1
				adapter->database = btd_gatt_database_new(adapter); <tag16>
				if (!adapter->database) {
					btd_error(adapter->dev_id,
							"Failed to create GATT database for adapter");
					adapters = g_slist_remove(adapters, adapter);
					return -EINVAL;
				}
				struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct btd_gatt_database *database;
					GError *gerr = NULL;
					const bdaddr_t *addr;

					DBG("Enter\n");
					if (!adapter)
						return NULL;

					database = new0(struct btd_gatt_database, 1); <tag20>
					database->adapter = btd_adapter_ref(adapter);
					database->db = gatt_db_new(); <tag21>
					database->device_states = queue_new();
					database->apps = queue_new();
					database->profiles = queue_new();
					database->ccc_callbacks = queue_new();

					addr = btd_adapter_get_address(adapter);
					const bdaddr_t *btd_adapter_get_address(struct btd_adapter *adapter)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						return &adapter->bdaddr;
					}
					database->le_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &gerr,
									BT_IO_OPT_SOURCE_BDADDR, addr,
									BT_IO_OPT_SOURCE_TYPE,
									btd_adapter_get_address_type(adapter),
									BT_IO_OPT_CID, ATT_CID,
									BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
									BT_IO_OPT_INVALID);
					if (!database->le_io) {
						error("Failed to start listening: %s", gerr->message);
						g_error_free(gerr);
						goto fail;
					}

					/* BR/EDR socket */
					DBG("listen l2cap\n");
					database->l2cap_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &gerr,
									BT_IO_OPT_SOURCE_BDADDR, addr,
									BT_IO_OPT_PSM, ATT_PSM,
									BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
									BT_IO_OPT_INVALID);
					if (database->l2cap_io == NULL) {
						error("Failed to start listening: %s", gerr->message);
						g_error_free(gerr);
						goto fail;
					}

					if (g_dbus_register_interface(btd_get_dbus_connection(),
										adapter_get_path(adapter),
										GATT_MANAGER_IFACE,
										manager_methods, NULL, NULL,
										database, NULL))
						DBG("GATT Manager registered for adapter: %s",
										adapter_get_path(adapter));
					//GATT Manager registered for adapter: /org/bluez/hci0

					register_core_services(database);
					static void register_core_services(struct btd_gatt_database *database)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						populate_gap_service(database);
						static void populate_gap_service(struct btd_gatt_database *database)
						{
							printf("jokerb %s:in %d.\n",__func__,__LINE__);
							bt_uuid_t uuid;
							struct gatt_db_attribute *service;

							/* Add the GAP service */
							bt_uuid16_create(&uuid, UUID_GAP);
							service = gatt_db_add_service(database->db, &uuid, true, 5);
							database->gap_handle = database_add_record(database, UUID_GAP, service,
												"Generic Access Profile");

							/*
							 * Device Name characteristic.
							 */
							bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME);
							gatt_db_service_add_characteristic(service, &uuid, BT_ATT_PERM_READ,
													BT_GATT_CHRC_PROP_READ,
													gap_device_name_read_cb,
													NULL, database);

							/*
							 * Device Appearance characteristic.
							 */
							bt_uuid16_create(&uuid, GATT_CHARAC_APPEARANCE);
							gatt_db_service_add_characteristic(service, &uuid, BT_ATT_PERM_READ,
													BT_GATT_CHRC_PROP_READ,
													gap_appearance_read_cb,
													NULL, database);

							gatt_db_service_set_active(service, true);
						}
						populate_gatt_service(database);
						static void populate_gatt_service(struct btd_gatt_database *database)
						{
							printf("jokerb %s:in %d.\n",__func__,__LINE__);
							bt_uuid_t uuid;
							struct gatt_db_attribute *service;

							/* Add the GATT service */
							bt_uuid16_create(&uuid, UUID_GATT);
							service = gatt_db_add_service(database->db, &uuid, true, 4);
							database->gatt_handle = database_add_record(database, UUID_GATT,
												service,
												"Generic Attribute Profile");

							bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED);
							database->svc_chngd = gatt_db_service_add_characteristic(service, &uuid,
										BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_INDICATE,
										NULL, NULL, database);

							database->svc_chngd_ccc = service_add_ccc(service, database, NULL, NULL,
															NULL);

							gatt_db_service_set_active(service, true);
						}
					}

					database->db_id = gatt_db_register(database->db, gatt_db_service_added,
											gatt_db_service_removed,
											database, NULL); <tag19>
					if (!database->db_id)
						goto fail;


					return database;

				fail:
					gatt_database_free(database);

					return NULL;
				}
#endif

				if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL) {
					/* Don't start advertising managers on non-LE controllers. */
					if (adapter->supported_settings & MGMT_SETTING_LE) {
						adapter->adv_manager = btd_adv_manager_new(adapter);
					} else {
						btd_info(adapter->dev_id,
							"LEAdvertisingManager skipped, LE unavailable");
					}
				}

#if 1
				db = btd_gatt_database_get_db(adapter->database);
				adapter->db_id = gatt_db_register(db, services_modified,
										services_modified,
										adapter, NULL); <tag23>
#endif

				load_config(adapter);
				static void load_config(struct btd_adapter *adapter)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					GKeyFile *key_file;
					char filename[PATH_MAX];
					struct stat st;
					GError *gerr = NULL;

					key_file = g_key_file_new();

					snprintf(filename, PATH_MAX, STORAGEDIR "/%s/settings",
										adapter_dir(adapter));
					#define STORAGEDIR "/userdata/lib/bluetooth"

					if (stat(filename, &st) < 0) {
						convert_config(adapter, filename, key_file);
						convert_device_storage(adapter);
					}

					g_key_file_load_from_file(key_file, filename, 0, NULL);

					/* Get alias */
					adapter->stored_alias = g_key_file_get_string(key_file, "General",
												"Alias", NULL);
					if (!adapter->stored_alias) {
						/* fallback */
						adapter->stored_alias = g_key_file_get_string(key_file,
										"General", "Name", NULL);
					}

					/* Get pairable timeout */
					adapter->pairable_timeout = g_key_file_get_integer(key_file, "General",
										"PairableTimeout", &gerr);
					if (gerr) {
						adapter->pairable_timeout = main_opts.pairto;
						g_error_free(gerr);
						gerr = NULL;
					}

					/* Get discoverable mode */
					adapter->stored_discoverable = g_key_file_get_boolean(key_file,
									"General", "Discoverable", &gerr);
					if (gerr) {
						adapter->stored_discoverable = false;
						g_error_free(gerr);
						gerr = NULL;
					}

					/* Get discoverable timeout */
					adapter->discoverable_timeout = g_key_file_get_integer(key_file,
								"General", "DiscoverableTimeout", &gerr);
					if (gerr) {
						adapter->discoverable_timeout = main_opts.discovto;
						g_error_free(gerr);
						gerr = NULL;
					}

					g_key_file_free(key_file);
				}
				fix_storage(adapter);
				load_drivers(adapter);
				static void load_drivers(struct btd_adapter *adapter)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					GSList *l;

					for (l = adapter_drivers; l; l = l->next)
						probe_driver(adapter, l->data);
					static void probe_driver(struct btd_adapter *adapter, gpointer user_data)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						struct btd_adapter_driver *driver = user_data;
						int err;

						if (driver->probe == NULL)
							return;

						err = driver->probe(adapter);
						if (err < 0) {
							btd_error(adapter->dev_id, "%s: %s (%d)", driver->name,
												strerror(-err), -err);
							return;
						}

						adapter->drivers = g_slist_prepend(adapter->drivers, driver); <tag24>
					}
				}
				btd_profile_foreach(probe_profile, adapter);
				void btd_profile_foreach(void (*func)(struct btd_profile *p, void *data),
												void *data)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					GSList *l, *next;

					for (l = profiles; l != NULL; l = next) {
						struct btd_profile *profile = l->data;

						next = g_slist_next(l);

						func(profile, data);
						static void probe_profile(struct btd_profile *profile, void *data)
						{
							printf("jokerb %s:in %d.\n",__func__,__LINE__);
							struct btd_adapter *adapter = data;
							int err;

							if (profile->adapter_probe == NULL)
								return;

							err = profile->adapter_probe(profile, adapter);
							if (err < 0) {
								btd_error(adapter->dev_id, "%s: %s (%d)", profile->name,
													strerror(-err), -err);
								return;
							}

							adapter->profiles = g_slist_prepend(adapter->profiles, profile); <tag25>
						}
					}

					for (l = ext_profiles; l != NULL; l = next) {
						struct ext_profile *profile = l->data;

						next = g_slist_next(l);

						func(&profile->p, data);
					}
				}
				clear_blocked(adapter);
				static int clear_blocked(struct btd_adapter *adapter)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					return btd_adapter_unblock_address(adapter, BDADDR_ANY, 0);
					int btd_adapter_unblock_address(struct btd_adapter *adapter,
									const bdaddr_t *bdaddr, uint8_t bdaddr_type)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						struct mgmt_cp_unblock_device cp;
						char addr[18];

						ba2str(bdaddr, addr);
						DBG("hci%u %s", adapter->dev_id, addr);

						memset(&cp, 0, sizeof(cp));
						bacpy(&cp.addr.bdaddr, bdaddr);
						cp.addr.type = bdaddr_type;

						if (mgmt_send(adapter->mgmt, MGMT_OP_UNBLOCK_DEVICE,
									adapter->dev_id, sizeof(cp), &cp,
									NULL, NULL, NULL) > 0)
							return 0;

						return -EIO;
					}
				}
				load_devices(adapter);
				static void load_devices(struct btd_adapter *adapter)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					char dirname[PATH_MAX];
					GSList *keys = NULL;
					GSList *ltks = NULL;
					GSList *irks = NULL;
					GSList *params = NULL;
					GSList *added_devices = NULL;
					DIR *dir;
					struct dirent *entry;

					snprintf(dirname, PATH_MAX, STORAGEDIR "/%s", adapter_dir(adapter));

					//dirname == /userdata/lib/bluetooth/68:89:5B:01:28:23 
					dir = opendir(dirname);
					if (!dir) {
						btd_error(adapter->dev_id,
								"Unable to open adapter storage directory: %s",
												dirname);
						return;
					}

					while ((entry = readdir(dir)) != NULL) {
						struct btd_device *device;
						char filename[PATH_MAX];
						GKeyFile *key_file;
						struct link_key_info *key_info;
						GSList *list, *ltk_info;
						struct irk_info *irk_info;
						struct conn_param *param;
						uint8_t bdaddr_type;

						if (entry->d_type == DT_UNKNOWN)
							entry->d_type = util_get_dt(dirname, entry->d_name);

						if (entry->d_type != DT_DIR || bachk(entry->d_name) < 0)
							continue;

						snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info",
									adapter_dir(adapter), entry->d_name);
						//filename == /userdata/lib/bluetooth/68:89:5B:01:28:23/04:57:91:CC:BB:0E/info

						key_file = g_key_file_new();
						g_key_file_new (void)
						{
						  GKeyFile *key_file;

						  key_file = g_slice_new0 (GKeyFile);
						  key_file->ref_count = 1;
						  g_key_file_init (key_file);
							g_key_file_init (GKeyFile *key_file)
							{  
							  key_file->current_group = g_slice_new0 (GKeyFileGroup);
							  key_file->groups = g_list_prepend (NULL, key_file->current_group);
							  key_file->group_hash = g_hash_table_new (g_str_hash, g_str_equal);
							  key_file->start_group = NULL;
							  key_file->parse_buffer = g_string_sized_new (128);
							  key_file->list_separator = ';';
							  key_file->flags = 0;
							  key_file->locales = g_strdupv ((gchar **)g_get_language_names ());
							}

						  return key_file;
						}
						g_key_file_load_from_file(key_file, filename, 0, NULL);

						/* GM: 获得 LinkKey信息 */
						key_info = get_key_info(key_file, entry->d_name); <tag26>
						if (key_info)
							keys = g_slist_append(keys, key_info);
						static struct link_key_info *get_key_info(GKeyFile *key_file, const char *peer)
						{
							printf("jokerb %s:in %d.\n",__func__,__LINE__);
							struct link_key_info *info = NULL;
							char *str;

							str = g_key_file_get_string(key_file, "LinkKey", "Key", NULL);
							if (!str || strlen(str) < 32)
								goto failed;

							info = g_new0(struct link_key_info, 1);

							str2ba(peer, &info->bdaddr);

							if (!strncmp(str, "0x", 2))
								str2buf(&str[2], info->key, sizeof(info->key));
							else
								str2buf(&str[0], info->key, sizeof(info->key));

							info->type = g_key_file_get_integer(key_file, "LinkKey", "Type", NULL);
							info->pin_len = g_key_file_get_integer(key_file, "LinkKey", "PINLength",
												NULL);

						failed:
							g_free(str);

							return info;
						}

						bdaddr_type = get_le_addr_type(key_file);

						/* GM: 获得LongTermKey */
						ltk_info = get_ltk_info(key_file, entry->d_name, bdaddr_type);
						ltks = g_slist_concat(ltks, ltk_info);

						irk_info = get_irk_info(key_file, entry->d_name, bdaddr_type);
						if (irk_info)
							irks = g_slist_append(irks, irk_info);

						/* GM: 获得 ConnectionParameters*/
						param = get_conn_param(key_file, entry->d_name, bdaddr_type);
						if (param)
							params = g_slist_append(params, param);

						list = g_slist_find_custom(adapter->devices, entry->d_name,
											device_address_cmp);
						if (list) {
							device = list->data;
							goto device_exist;
						}

						device = device_create_from_storage(adapter, entry->d_name, key_file);
						struct btd_device *device_create_from_storage(struct btd_adapter *adapter,
										const char *address, GKeyFile *key_file)
						{
							printf("jokerb %s:in %d.\n",__func__,__LINE__);
							struct btd_device *device;
							const bdaddr_t *src;
							char srcaddr[18];

							DBG("address %s", address);

							device = device_new(adapter, address);
							if (device == NULL)
								return NULL;
							static struct btd_device *device_new(struct btd_adapter *adapter,
											const char *address)
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								char *address_up;
								struct btd_device *device;
								const char *adapter_path = adapter_get_path(adapter);

								DBG("address %s", address);

								device = g_try_malloc0(sizeof(struct btd_device)); <tag29>
								if (device == NULL)
									return NULL;

								device->tx_power = 127;

								device->db = gatt_db_new();
								if (!device->db) {
									g_free(device);
									return NULL;
								}

								memset(device->ad_flags, INVALID_FLAGS, sizeof(device->ad_flags));

								device->ad = bt_ad_new();
								if (!device->ad) {
									device_free(device);
									return NULL;
								}

								address_up = g_ascii_strup(address, -1);
								device->path = g_strdup_printf("%s/dev_%s", adapter_path, address_up); <tag28>
								g_strdelimit(device->path, ":", '_');
								g_free(address_up);

								str2ba(address, &device->bdaddr); <tag30>

								device->client_dbus = btd_gatt_client_new(device);
								if (!device->client_dbus) {
									error("Failed to create btd_gatt_client");
									device_free(device);
									return NULL;
								}

								DBG("Creating device %s", device->path);

								if (g_dbus_register_interface(dbus_conn,
												device->path, DEVICE_INTERFACE,
												device_methods, NULL,
												device_properties, device,
												device_free) == FALSE) {
									error("Unable to register device interface for %s", address);
									device_free(device);
									return NULL;
								}

								device->adapter = adapter; <tag31>
								device->temporary = true; <tag32>

								device->db_id = gatt_db_register(device->db, gatt_service_added,
												gatt_service_removed, device, NULL);

								return btd_device_ref(device);
							}

							src = btd_adapter_get_address(adapter);
							ba2str(src, srcaddr);

							//key_file 为文件系统内的已配对的蓝牙设备的info文件.
							convert_info(device, key_file);
							static void convert_info(struct btd_device *device, GKeyFile *key_file)
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								char filename[PATH_MAX];
								char adapter_addr[18];
								char device_addr[18];
								char **uuids;
								char *str;
								gsize length = 0;

								/* Load device profile list from legacy properties */
								uuids = g_key_file_get_string_list(key_file, "General", "SDPServices",NULL, NULL);
								if (uuids) //GM is NULL
									load_services(device, uuids);

								uuids = g_key_file_get_string_list(key_file, "General", "GATTServices",NULL, NULL);
								if (uuids) //GM is NULL
									load_services(device, uuids);

								if (!device->uuids) //GM: into here.
									return;

								/* Remove old entries so they are not loaded again */
								g_key_file_remove_key(key_file, "General", "SDPServices", NULL);
								g_key_file_remove_key(key_file, "General", "GATTServices", NULL);

								ba2str(btd_adapter_get_address(device->adapter), adapter_addr);
								ba2str(&device->bdaddr, device_addr);
								snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
										device_addr);

								str = g_key_file_to_data(key_file, &length, NULL);
								g_file_set_contents(filename, str, length, NULL);
								g_free(str);

								store_device_info(device);
							}

							load_info(device, srcaddr, address, key_file);
							static void load_info(struct btd_device *device, const char *local,
										const char *peer, GKeyFile *key_file)
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								char *str;
								gboolean store_needed = FALSE;
								gboolean blocked;
								char **uuids;
								int source, vendor, product, version;
								char **techno, **t;

								/* Load device name from storage info file, if that fails fall back to
								 * the cache.
								 */
								str = g_key_file_get_string(key_file, "General", "Name", NULL);
								//printf("jokerb %s:in %d. name %s\n",__func__,__LINE__, str);
								if (str == NULL) {
									str = load_cached_name(device, local, peer);
									if (str)
										store_needed = TRUE;
								}

								if (str) {
									strcpy(device->name, str);
									g_free(str);
								}

								/* Load alias */
								device->alias = g_key_file_get_string(key_file, "General", "Alias",NULL);

								/* Load class */
								str = g_key_file_get_string(key_file, "General", "Class", NULL);
								if (str) {
									uint32_t class;

									if (sscanf(str, "%x", &class) == 1)
										device->class = class;
									g_free(str);
								}

								/* Load appearance */
								str = g_key_file_get_string(key_file, "General", "Appearance", NULL);
								if (str) {
									device->appearance = strtol(str, NULL, 16);
									g_free(str);
								}

								/* Load device technology */
								techno = g_key_file_get_string_list(key_file, "General",
												"SupportedTechnologies", NULL, NULL);
								if (!techno)
									goto next;

								for (t = techno; *t; t++) {
									if (g_str_equal(*t, "BR/EDR"))
										device->bredr = true;
									else if (g_str_equal(*t, "LE"))
										device->le = true;
									else
										error("Unknown device technology");
								}

								if (!device->le) {
									device->bdaddr_type = BDADDR_BREDR;
								} else {
									str = g_key_file_get_string(key_file, "General",
													"AddressType", NULL);

									if (str && g_str_equal(str, "public"))
										device->bdaddr_type = BDADDR_LE_PUBLIC;
									else if (str && g_str_equal(str, "static"))
										device->bdaddr_type = BDADDR_LE_RANDOM;
									else
										error("Unknown LE device technology");

									g_free(str);

									device->local_csrk = load_csrk(key_file, "LocalSignatureKey");
									device->remote_csrk = load_csrk(key_file, "RemoteSignatureKey");
								}

								g_strfreev(techno);

							next:
								/* Load trust */
								device->trusted = g_key_file_get_boolean(key_file, "General",
														"Trusted", NULL);

								/* Load device blocked */
								blocked = g_key_file_get_boolean(key_file, "General", "Blocked", NULL);
								if (blocked)
									device_block(device, FALSE);

								/* Load device profile list */
								uuids = g_key_file_get_string_list(key_file, "General", "Services",
													NULL, NULL);
								if (uuids) {
									printf("jokerb %s:in %d.\n",__func__,__LINE__); //
									load_services(device, uuids); <tag33>
									static void load_services(struct btd_device *device, char **uuids)
									{
										printf("jokerb %s:in %d.\n",__func__,__LINE__);
										char **uuid;

										for (uuid = uuids; *uuid; uuid++) {
											if (g_slist_find_custom(device->uuids,*uuid,bt_uuid_strcmp))
												continue;

											device->uuids = g_slist_insert_sorted(device->uuids,
																g_strdup(*uuid),
																bt_uuid_strcmp);
										}

										g_strfreev(uuids);
									}

									/* Discovered services restored from storage */
									device->bredr_state.svc_resolved = true; <tag37>
								}

								/* Load device id */
								source = g_key_file_get_integer(key_file, "DeviceID", "Source", NULL);
								if (source) {
									vendor = g_key_file_get_integer(key_file, "DeviceID",
														"Vendor", NULL);

									product = g_key_file_get_integer(key_file, "DeviceID",
														"Product", NULL);

									version = g_key_file_get_integer(key_file, "DeviceID",
														"Version", NULL);

									btd_device_set_pnpid(device, source, vendor, product, version);
								}

								if (store_needed)
									store_device_info(device);

								printf("jokerb %s:in %d.\n",__func__,__LINE__);
							}

							/* GM: 加载attributes文件内的配置, 没有该文件. 目前只有info文件. */
							load_att_info(device, srcaddr, address);
							static void load_att_info(struct btd_device *device, const char *local,
											const char *peer)
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								char filename[PATH_MAX];
								GKeyFile *key_file;
								char *prim_uuid, *str;
								char **groups, **handle, *service_uuid;
								struct gatt_primary *prim;
								uuid_t uuid;
								char tmp[3];
								int i;

								sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
								prim_uuid = bt_uuid2string(&uuid);

								snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/attributes", local,
										peer);

								key_file = g_key_file_new();
								g_key_file_load_from_file(key_file, filename, 0, NULL);
								groups = g_key_file_get_groups(key_file, NULL);

								for (handle = groups; *handle; handle++) {
									gboolean uuid_ok;
									int end;

									str = g_key_file_get_string(key_file, *handle, "UUID", NULL);
									if (!str)
										continue;

									uuid_ok = g_str_equal(str, prim_uuid);
									g_free(str);

									if (!uuid_ok)
										continue;

									str = g_key_file_get_string(key_file, *handle, "Value", NULL);
									if (!str)
										continue;

									end = g_key_file_get_integer(key_file, *handle,
													"EndGroupHandle", NULL);
									if (end == 0) {
										g_free(str);
										continue;
									}

									prim = g_new0(struct gatt_primary, 1);
									prim->range.start = atoi(*handle);
									prim->range.end = end;

									switch (strlen(str)) {
									case 4:
										uuid.type = SDP_UUID16;
										sscanf(str, "%04hx", &uuid.value.uuid16);
									break;
									case 8:
										uuid.type = SDP_UUID32;
										sscanf(str, "%08x", &uuid.value.uuid32);
										break;
									case 32:
										uuid.type = SDP_UUID128;
										memset(tmp, 0, sizeof(tmp));
										for (i = 0; i < 16; i++) {
											memcpy(tmp, str + (i * 2), 2);
											uuid.value.uuid128.data[i] =
													(uint8_t) strtol(tmp, NULL, 16);
										}
										break;
									default:
										g_free(str);
										g_free(prim);
										continue;
									}

									service_uuid = bt_uuid2string(&uuid);
									memcpy(prim->uuid, service_uuid, MAX_LEN_UUID_STR);
									free(service_uuid);
									g_free(str);

									device->primaries = g_slist_append(device->primaries, prim);
								}

								g_strfreev(groups);
								g_key_file_free(key_file);
								free(prim_uuid);
							}

							return device;
						}
						if (!device)
							goto free;

						btd_device_set_temporary(device, false);
						adapter->devices = g_slist_append(adapter->devices, device); <tag35>

						/* TODO: register services from pre-loaded list of primaries */

						added_devices = g_slist_append(added_devices, device);

				device_exist:
						if (key_info) {
							device_set_paired(device, BDADDR_BREDR); <tag36>
							void device_set_paired(struct btd_device *dev, uint8_t bdaddr_type)
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								struct bearer_state *state = get_state(dev, bdaddr_type);
								static struct bearer_state *get_state(struct btd_device *dev,
															uint8_t bdaddr_type)
								{
									printf("jokerb %s:in %d.\n",__func__,__LINE__);
									if (bdaddr_type == BDADDR_BREDR)
										return &dev->bredr_state;
									else
										return &dev->le_state;
								}

								if (state->paired)
									return;

								state->paired = true;

								/* If the other bearer state was alraedy true we don't need to
								 * send any property signals.
								 */
								if (dev->bredr_state.paired == dev->le_state.paired)
									return;

								if (!state->svc_resolved) {
									dev->pending_paired = true;
									return;
								}

								g_dbus_emit_property_changed(dbus_conn, dev->path,
													DEVICE_INTERFACE, "Paired");
							}
							device_set_bonded(device, BDADDR_BREDR); <tag39>
							void device_set_bonded(struct btd_device *device, uint8_t bdaddr_type)
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								if (!device)
									return;

								DBG("");

								if (bdaddr_type == BDADDR_BREDR)
									device->bredr_state.bonded = true;
								else
									device->le_state.bonded = true;

								btd_device_set_temporary(device, false);
							}
						}

						if (ltk_info) {
							device_set_paired(device, bdaddr_type);
							device_set_bonded(device, bdaddr_type);
						}

				free:
						g_key_file_free(key_file);
					}

					closedir(dir);

					//keys队列, 包含所有的info文件信息
					load_link_keys(adapter, keys, main_opts.debug_keys);
					static void load_link_keys(struct btd_adapter *adapter, GSList *keys,
												bool debug_keys)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						struct mgmt_cp_load_link_keys *cp;
						struct mgmt_link_key_info *key;
						size_t key_count, cp_size;
						unsigned int id;
						GSList *l;

						/*
						 * If the controller does not support BR/EDR operation,
						 * there is no point in trying to load the link keys into
						 * the kernel.
						 *
						 * This is an optimization for Low Energy only controllers.
						 */
						if (!(adapter->supported_settings & MGMT_SETTING_BREDR))
							return;

						key_count = g_slist_length(keys);

						DBG("hci%u keys %zu debug_keys %d", adapter->dev_id, key_count,
													debug_keys);

						cp_size = sizeof(*cp) + (key_count * sizeof(*key));

						cp = g_try_malloc0(cp_size);
						if (cp == NULL) {
							btd_error(adapter->dev_id, "No memory for link keys for hci%u",
												adapter->dev_id);
							return;
						}

						/*
						 * Even if the list of stored keys is empty, it is important to
						 * load an empty list into the kernel. That way it is ensured
						 * that no old keys from a previous daemon are present.
						 *
						 * In addition it is also the only way to toggle the different
						 * behavior for debug keys.
						 */
						cp->debug_keys = debug_keys;
						cp->key_count = htobs(key_count);

						for (l = keys, key = cp->keys; l != NULL; l = g_slist_next(l), key++) {
							struct link_key_info *info = l->data;

							bacpy(&key->addr.bdaddr, &info->bdaddr);
							key->addr.type = BDADDR_BREDR;
							key->type = info->type;
							memcpy(key->val, info->key, 16);
							key->pin_len = info->pin_len;
						}

						id = mgmt_send(adapter->mgmt, MGMT_OP_LOAD_LINK_KEYS,
									adapter->dev_id, cp_size, cp,
									load_link_keys_complete, adapter, NULL);

						g_free(cp);

						if (id == 0)
							btd_error(adapter->dev_id, "Failed to load link keys for hci%u",
												adapter->dev_id);
					}
					g_slist_free_full(keys, g_free);

					load_ltks(adapter, ltks);
					g_slist_free_full(ltks, g_free);
					load_irks(adapter, irks);
					g_slist_free_full(irks, g_free);
					load_conn_params(adapter, params);
					static void load_conn_params(struct btd_adapter *adapter, GSList *params)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						struct mgmt_cp_load_conn_param *cp;
						struct mgmt_conn_param *param;
						size_t param_count, cp_size;
						unsigned int id;
						GSList *l;

						/*
						 * If the controller does not support Low Energy operation,
						 * there is no point in trying to load the connection
						 * parameters into the kernel.
						 */
						if (!(adapter->supported_settings & MGMT_SETTING_LE))
							return;

						param_count = g_slist_length(params);

						DBG("hci%u conn params %zu", adapter->dev_id, param_count);

						cp_size = sizeof(*cp) + (param_count * sizeof(*param));

						cp = g_try_malloc0(cp_size);
						if (cp == NULL) {
							btd_error(adapter->dev_id,
								"Failed to allocate memory for connection parameters");
							return;
						}

						cp->param_count = htobs(param_count);

						for (l = params, param = cp->params; l; l = g_slist_next(l), param++) {
							struct conn_param *info = l->data;

							bacpy(&param->addr.bdaddr, &info->bdaddr);
							param->addr.type = info->bdaddr_type;
							param->min_interval = htobs(info->min_interval);
							param->max_interval = htobs(info->max_interval);
							param->latency = htobs(info->latency);
							param->timeout = htobs(info->timeout);
						}

						id = mgmt_send(adapter->mgmt, MGMT_OP_LOAD_CONN_PARAM, adapter->dev_id,
								cp_size, cp, load_conn_params_complete, adapter, NULL);

						g_free(cp);

						if (id == 0)
							btd_error(adapter->dev_id, "Load connection parameters failed");
					}
					g_slist_free_full(params, g_free);

					g_slist_free_full(added_devices, probe_devices);
					static void probe_devices(void *user_data)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						struct btd_device *device = user_data;

						device_probe_profiles(device, btd_device_get_uuids(device));
						GSList *btd_device_get_uuids(struct btd_device *device)
						{
							return device->uuids;
						}
						void device_probe_profiles(struct btd_device *device, GSList *uuids)
						{
							printf("jokerb %s:in %d.\n",__func__,__LINE__);
							struct probe_data d = { device, uuids };
							char addr[18];

							ba2str(&device->bdaddr, addr);

							if (device->blocked) {
								DBG("Skipping profiles for blocked device %s", addr);
								goto add_uuids;
							}

							DBG("Probing profiles for device %s", addr);
							//Probing profiles for device 04:57:91:CC:BB:0E

							btd_profile_foreach(dev_probe, &d);
							void btd_profile_foreach(void (*func)(struct btd_profile *p, void *data),
															void *data)
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								GSList *l, *next;

								for (l = profiles; l != NULL; l = next) {
									struct btd_profile *profile = l->data;

									next = g_slist_next(l);

									func(profile, data);
								}

								for (l = ext_profiles; l != NULL; l = next) {
									struct ext_profile *profile = l->data;

									next = g_slist_next(l);

									func(&profile->p, data);
								}
							}
							static void dev_probe(struct btd_profile *p, void *user_data)
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								struct probe_data *d = user_data;
								struct btd_service *service;

								service = probe_service(d->dev, p, d->uuids);
								if (!service)
									return;
								static struct btd_service *probe_service(struct btd_device *device,
														struct btd_profile *profile,
														GSList *uuids)
								{
									printf("jokerb %s:in %d.\n",__func__,__LINE__);
									struct btd_service *service;

									if (profile->device_probe == NULL)
										return NULL;

									if (!device_match_profile(device, profile, uuids))
										return NULL;
									static bool device_match_profile(struct btd_device *device,
														struct btd_profile *profile,
														GSList *uuids)
									{
										printf("jokerb %s:in %d.\n",__func__,__LINE__);
										if (profile->remote_uuid == NULL)
											return false;

										if (g_slist_find_custom(uuids, profile->remote_uuid,
																bt_uuid_strcmp) == NULL)
											return false;

										return true;
									}

									service = service_create(device, profile);
									struct btd_service *service_create(struct btd_device *device,
															struct btd_profile *profile)
									{
										printf("jokerb %s:in %d.\n",__func__,__LINE__);
										struct btd_service *service;

										service = g_try_new0(struct btd_service, 1); <tag42>
										if (!service) {
											error("service_create: failed to alloc memory");
											return NULL;
										}

										service->ref = 1;
										service->device = device; /* Weak ref */ <tag44>
										service->profile = profile; <tag45>
										service->state = BTD_SERVICE_STATE_UNAVAILABLE; <tag46>

										return service;
									}

									if (service_probe(service)) {
										btd_service_unref(service);
										return NULL;
									}
									int service_probe(struct btd_service *service)
									{
										printf("jokerb %s:in %d.\n",__func__,__LINE__);
										char addr[18];
										int err;

										btd_assert(service->state == BTD_SERVICE_STATE_UNAVAILABLE);

										err = service->profile->device_probe(service);
										//avrcp_controller_probe
										//a2dp_sink_probe
										//hfp_device_probe
										if (err == 0) {
											/* GM: 在这里返回. */
											change_state(service, BTD_SERVICE_STATE_DISCONNECTED, 0); <tag49>
											return 0;
										}

										ba2str(device_get_address(service->device), addr);
										error("%s profile probe failed for %s",
													service->profile->name, addr);

										return err;
									}

									/* Only set auto connect if profile has set the flag and can really
									 * accept connections.
									 */
									if (profile->auto_connect && profile->accept) //GM: no into
										device_set_auto_connect(device, TRUE);
										static void device_set_auto_connect(struct btd_device *device,
																			gboolean enable)
										{
											printf("jokerb %s:in %d.\n",__func__,__LINE__);
											char addr[18];

											if (!device || !device->le)
												return;

											ba2str(&device->bdaddr, addr);

											DBG("%s auto connect: %d", addr, enable);

											if (device->auto_connect == enable)
												return;

											device->auto_connect = enable;

											/* Disabling auto connect */
											if (enable == FALSE) {
												adapter_connect_list_remove(device->adapter, device);
												adapter_auto_connect_remove(device->adapter, device);
												return;
											}

											/* Enabling auto connect */
											adapter_auto_connect_add(device->adapter, device);
											void adapter_auto_connect_add(struct btd_adapter *adapter,
																struct btd_device *device)
											{
												printf("jokerb %s:in %d.\n",__func__,__LINE__);
												struct mgmt_cp_add_device cp;
												const bdaddr_t *bdaddr;
												uint8_t bdaddr_type;
												unsigned int id;

												if (!kernel_conn_control)
													return;

												if (g_slist_find(adapter->connect_list, device)) {
													DBG("ignoring already added device %s",
																	device_get_path(device));
													return;
												}

												bdaddr = device_get_address(device);
												bdaddr_type = btd_device_get_bdaddr_type(device);

												if (bdaddr_type == BDADDR_BREDR) {
													DBG("auto-connection feature is not avaiable for BR/EDR");
													return;
												}

												memset(&cp, 0, sizeof(cp));
												bacpy(&cp.addr.bdaddr, bdaddr);
												cp.addr.type = bdaddr_type;
												cp.action = 0x02;

												id = mgmt_send(adapter->mgmt, MGMT_OP_ADD_DEVICE,
														adapter->dev_id, sizeof(cp), &cp, add_device_complete,
														adapter, NULL);
												if (id == 0)
													return;
												<tag47>
												adapter->connect_list = g_slist_append(adapter->connect_list, device);
											}

											if (device->attrib) {
												DBG("Already connected");
												return;
											}

											adapter_connect_list_add(device->adapter, device); <tag50>
											int adapter_connect_list_add(struct btd_adapter *adapter,
																struct btd_device *device)
											{
												printf("jokerb %s:in %d.\n",__func__,__LINE__);
												/*
												 * If the adapter->connect_le device is getting added back to
												 * the connect list it probably means that the connect attempt
												 * failed and hence we should clear this pointer
												 */
												if (device == adapter->connect_le)
													adapter->connect_le = NULL;

												/*
												 * If kernel background scanning is supported then the
												 * adapter_auto_connect_add() function is used to maintain what to
												 * connect.
												 */
												if (kernel_conn_control)
													return 0;

												if (g_slist_find(adapter->connect_list, device)) {
													DBG("ignoring already added device %s",
																	device_get_path(device));
													goto done;
												}

												if (!(adapter->supported_settings & MGMT_SETTING_LE)) {
													btd_error(adapter->dev_id,
														"Can't add %s to non-LE capable adapter connect list",
																	device_get_path(device));
													return -ENOTSUP;
												}

												adapter->connect_list = g_slist_append(adapter->connect_list, device);
												DBG("%s added to %s's connect_list", device_get_path(device),
																		adapter->system_name);

											done:
												if (!(adapter->current_settings & MGMT_SETTING_POWERED))
													return 0;

												trigger_passive_scanning(adapter);

												return 0;
											}
										}

									return service;
								}

								d->dev->services = g_slist_append(d->dev->services, service); <tag52>
							}

						add_uuids:
							device_add_uuids(device, uuids);
							static void device_add_uuids(struct btd_device *device, GSList *uuids)
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								GSList *l;
								bool changed = false;

								for (l = uuids; l != NULL; l = g_slist_next(l)) {
									GSList *match = g_slist_find_custom(device->uuids, l->data,
														bt_uuid_strcmp);
									if (match)
										continue;

									changed = true;
									device->uuids = g_slist_insert_sorted(device->uuids,
													g_strdup(l->data),
													bt_uuid_strcmp);
								}

								if (changed)
									g_dbus_emit_property_changed(dbus_conn, device->path,
													DEVICE_INTERFACE, "UUIDs");
							}
						}
					}
				}

				/* retrieve the active connections: address the scenario where
				 * the are active connections before the daemon've started */
				if (adapter->current_settings & MGMT_SETTING_POWERED) {
					load_connections(adapter);
				}
					static void load_connections(struct btd_adapter *adapter)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						DBG("sending get connections command for index %u", adapter->dev_id);
						//sending get connections command for index 0

						if (mgmt_send(adapter->mgmt, MGMT_OP_GET_CONNECTIONS,
									adapter->dev_id, 0, NULL,
									get_connections_complete, adapter, NULL) > 0)
							return;

						btd_error(adapter->dev_id, "Failed to get connections for index %u",
												adapter->dev_id);
					}

				adapter->initialized = TRUE; <tag54>

				if (main_opts.did_source) {
					/* DeviceID record is added by sdpd-server before any other
					 * record is registered. */
					adapter_service_insert(adapter, sdp_record_find(0x10000));
					set_did(adapter, main_opts.did_vendor, main_opts.did_product,
							main_opts.did_version, main_opts.did_source);
				}

				DBG("Adapter %s registered", adapter->path);

				return 0;
			}

			/*
			 * Register all event notification handlers for controller.
			 *
			 * The handlers are registered after a succcesful read of the
			 * controller info. From now on they can track updates and
			 * notifications.
			 */
			mgmt_register(adapter->mgmt, MGMT_EV_NEW_SETTINGS, adapter->dev_id,
							new_settings_callback, adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_CLASS_OF_DEV_CHANGED,
								adapter->dev_id,
								dev_class_changed_callback,
								adapter, NULL);
			mgmt_register(adapter->mgmt, MGMT_EV_LOCAL_NAME_CHANGED,
								adapter->dev_id,
								local_name_changed_callback,
								adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_DISCOVERING,
								adapter->dev_id,
								discovering_callback,
								adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_FOUND,
								adapter->dev_id,
								device_found_callback,
								adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_DISCONNECTED,
								adapter->dev_id,
								disconnected_callback,
								adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_CONNECTED,
								adapter->dev_id,
								connected_callback,
								adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_CONNECT_FAILED,
								adapter->dev_id,
								connect_failed_callback,
								adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_UNPAIRED,
								adapter->dev_id,
								unpaired_callback,
								adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_AUTH_FAILED,
								adapter->dev_id,
								auth_failed_callback,
								adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_NEW_LINK_KEY,
								adapter->dev_id,
								new_link_key_callback,
								adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_NEW_LONG_TERM_KEY,
								adapter->dev_id,
								new_long_term_key_callback,
								adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_NEW_CSRK,
								adapter->dev_id,
								new_csrk_callback,
								adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_NEW_IRK,
								adapter->dev_id,
								new_irk_callback,
								adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_NEW_CONN_PARAM,
								adapter->dev_id,
								new_conn_param,
								adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_BLOCKED,
								adapter->dev_id,
								device_blocked_callback,
								adapter, NULL);
			mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_UNBLOCKED,
								adapter->dev_id,
								device_unblocked_callback,
								adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_PIN_CODE_REQUEST,
								adapter->dev_id,
								pin_code_request_callback,
								adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_USER_CONFIRM_REQUEST,
								adapter->dev_id,
								user_confirm_request_callback,
								adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_USER_PASSKEY_REQUEST,
								adapter->dev_id,
								user_passkey_request_callback,
								adapter, NULL);

			mgmt_register(adapter->mgmt, MGMT_EV_PASSKEY_NOTIFY,
								adapter->dev_id,
								user_passkey_notify_callback,
								adapter, NULL);

			set_dev_class(adapter);
			static void set_dev_class(struct btd_adapter *adapter)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct mgmt_cp_set_dev_class cp;

				/*
				 * If the controller does not support BR/EDR operation,
				 * there is no point in trying to set a major and minor
				 * class value.
				 *
				 * This is an optimization for Low Energy only controllers.
				 */
				if (!(adapter->supported_settings & MGMT_SETTING_BREDR))
					return;

				memset(&cp, 0, sizeof(cp));

				/*
				 * Silly workaround for a really stupid kernel bug :(
				 *
				 * All current kernel versions assign the major and minor numbers
				 * straight to dev_class[0] and dev_class[1] without considering
				 * the proper bit shifting.
				 *
				 * To make this work, shift the value in userspace for now until
				 * we get a fixed kernel version.
				 */
				cp.major = adapter->major_class & 0x1f;
				cp.minor = adapter->minor_class << 2;

				DBG("sending set device class command for index %u", adapter->dev_id);

				if (mgmt_send(adapter->mgmt, MGMT_OP_SET_DEV_CLASS,
							adapter->dev_id, sizeof(cp), &cp,
							set_dev_class_complete, adapter, NULL) > 0)
					return;
				static void set_dev_class_complete(uint8_t status, uint16_t length,
									const void *param, void *user_data)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct btd_adapter *adapter = user_data;

					if (status != MGMT_STATUS_SUCCESS) {
						btd_error(adapter->dev_id,
								"Failed to set device class: %s (0x%02x)",
										mgmt_errstr(status), status);
						return;
					}

					/*
					 * The parameters are identical and also the task that is
					 * required in both cases. So it is safe to just call the
					 * event handling functions here.
					 */
					dev_class_changed_callback(adapter->dev_id, length, param, adapter);
				}

				btd_error(adapter->dev_id,
					"Failed to set class of device for index %u", adapter->dev_id);
			}

			set_name(adapter, btd_adapter_get_name(adapter));
			const char *btd_adapter_get_name(struct btd_adapter *adapter)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				if (adapter->stored_alias)
					return adapter->stored_alias;

				if (adapter->system_name)
					return adapter->system_name;

				return NULL;
			}
			static int set_name(struct btd_adapter *adapter, const char *name)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct mgmt_cp_set_local_name cp;
				char maxname[MAX_NAME_LENGTH + 1];

				memset(maxname, 0, sizeof(maxname));
				strncpy(maxname, name, MAX_NAME_LENGTH);

				if (!g_utf8_validate(maxname, -1, NULL)) {
					btd_error(adapter->dev_id,
						"Name change failed: supplied name isn't valid UTF-8");
					return -EINVAL;
				}

				memset(&cp, 0, sizeof(cp));
				strncpy((char *) cp.name, maxname, sizeof(cp.name) - 1);

				DBG("sending set local name command for index %u", adapter->dev_id);

				if (mgmt_send(adapter->mgmt, MGMT_OP_SET_LOCAL_NAME,
							adapter->dev_id, sizeof(cp), &cp,
							set_local_name_complete, adapter, NULL) > 0)
					return 0;
					static void set_local_name_complete(uint8_t status, uint16_t length,
										const void *param, void *user_data)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						struct btd_adapter *adapter = user_data;

						if (status != MGMT_STATUS_SUCCESS) {
							btd_error(adapter->dev_id,
									"Failed to set local name: %s (0x%02x)",
											mgmt_errstr(status), status);
							return;
						}

						/*
						 * The parameters are identical and also the task that is
						 * required in both cases. So it is safe to just call the
						 * event handling functions here.
						 */
						local_name_changed_callback(adapter->dev_id, length, param, adapter);
						static void local_name_changed_callback(uint16_t index, uint16_t length,
											const void *param, void *user_data)
						{
							printf("jokerb %s:in %d.\n",__func__,__LINE__);
							struct btd_adapter *adapter = user_data;
							const struct mgmt_cp_set_local_name *rp = param;

							if (length < sizeof(*rp)) {
								btd_error(adapter->dev_id,
										"Wrong size of local name changed parameters");
								return;
							}

							if (!g_strcmp0(adapter->short_name, (const char *) rp->short_name) &&
									!g_strcmp0(adapter->name, (const char *) rp->name))
								return;

							DBG("Name: %s", rp->name);
							DBG("Short name: %s", rp->short_name);

							g_free(adapter->name);
							adapter->name = g_strdup((const char *) rp->name); <tag55>

							g_free(adapter->short_name);
							adapter->short_name = g_strdup((const char *) rp->short_name);

							/*
							 * Changing the name (even manually via HCI) will update the
							 * current alias property.
							 *
							 * In case the name is empty, use the short name.
							 *
							 * There is a difference between the stored alias (which is
							 * configured by the user) and the current alias. The current
							 * alias is temporary for the lifetime of the daemon.
							 */
							if (adapter->name && adapter->name[0] != '\0') {
								g_free(adapter->current_alias);
								adapter->current_alias = g_strdup(adapter->name);
							} else {
								g_free(adapter->current_alias);
								adapter->current_alias = g_strdup(adapter->short_name);
							}

							DBG("Current alias: %s", adapter->current_alias);

							if (!adapter->current_alias)
								return;

							g_dbus_emit_property_changed(dbus_conn, adapter->path,
												ADAPTER_INTERFACE, "Alias");

							attrib_gap_set(adapter, GATT_CHARAC_DEVICE_NAME,
										(const uint8_t *) adapter->current_alias,
											strlen(adapter->current_alias));
						}
					}

				btd_error(adapter->dev_id, "Failed to set local name for index %u",
										adapter->dev_id);

				return -EIO;
			}

			if (!(adapter->current_settings & MGMT_SETTING_BONDABLE)) //GM here
				set_mode(adapter, MGMT_OP_SET_BONDABLE, 0x01);

			if (!kernel_conn_control)
				set_mode(adapter, MGMT_OP_SET_CONNECTABLE, 0x01);
			else if (adapter->current_settings & MGMT_SETTING_CONNECTABLE)
				set_mode(adapter, MGMT_OP_SET_CONNECTABLE, 0x00);

			if (adapter->stored_discoverable && !adapter->discoverable_timeout)
				set_discoverable(adapter, 0x01, 0);

			if (adapter->current_settings & MGMT_SETTING_POWERED) //GM here
				adapter_start(adapter);
			static void adapter_start(struct btd_adapter *adapter)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				g_dbus_emit_property_changed(dbus_conn, adapter->path,
									ADAPTER_INTERFACE, "Powered");

				DBG("adapter %s has been enabled", adapter->path);
				//adapter /org/bluez/hci0 has been enabled

				trigger_passive_scanning(adapter);
				static void trigger_passive_scanning(struct btd_adapter *adapter)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					if (!(adapter->current_settings & MGMT_SETTING_LE))
						return;

					DBG("");

					if (adapter->passive_scan_timeout > 0) {
						g_source_remove(adapter->passive_scan_timeout);
						adapter->passive_scan_timeout = 0;
					}

					/*
					 * When the kernel background scanning is available, there is
					 * no need to start any discovery. The kernel will keep scanning
					 * as long as devices are in its auto-connection list.
					 */
					if (kernel_conn_control)
						return;

					/*
					 * If any client is running a discovery right now, then do not
					 * even try to start passive scanning.
					 *
					 * The discovery procedure is using interleaved scanning and
					 * thus will discover Low Energy devices as well.
					 */
					if (adapter->discovery_list)
						return;

					if (adapter->discovery_enable == 0x01)
						return;

					/*
					 * In case the discovery is suspended (for example for an ongoing
					 * pairing attempt), then also do not start passive scanning.
					 */
					if (adapter->discovery_suspended)
						return;

					/*
					 * If the list of connectable Low Energy devices is empty,
					 * then do not start passive scanning.
					 */
					if (!adapter->connect_list)
						return;

					adapter->passive_scan_timeout = g_timeout_add_seconds(CONN_SCAN_TIMEOUT,
									passive_scanning_timeout, adapter);
				}
			}

			return;

		failed:
			/*
			 * Remove adapter from list in case of a failure.
			 *
			 * Leaving an adapter structure around for a controller that can
			 * not be initilized makes no sense at the moment.
			 *
			 * This is a simplification to avoid constant checks if the
			 * adapter is ready to do anything.
			 */
			adapter_list = g_list_remove(adapter_list, adapter);

			btd_adapter_unref(adapter);
		}

		btd_error(adapter->dev_id,
				"Failed to read controller info for index %u", index);

		adapter_list = g_list_remove(adapter_list, adapter);

		btd_adapter_unref(adapter);
	}
	mgmt_register(mgmt_master, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
						index_removed, NULL, NULL);

	DBG("sending read index list command");

	if (mgmt_send(mgmt_master, MGMT_OP_READ_INDEX_LIST,
				MGMT_INDEX_NONE, 0, NULL,
				read_index_list_complete, NULL, NULL) > 0)
		return;
	static void read_index_list_complete(uint8_t status, uint16_t length,
						const void *param, void *user_data)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		const struct mgmt_rp_read_index_list *rp = param;
		uint16_t num;
		int i;

		if (status != MGMT_STATUS_SUCCESS) {
			error("Failed to read index list: %s (0x%02x)",
							mgmt_errstr(status), status);
			return;
		}

		if (length < sizeof(*rp)) {
			error("Wrong size of read index list response");
			return;
		}

		num = btohs(rp->num_controllers);

		DBG("Number of controllers: %d", num);
		//Number of controllers: 1

		if (num * sizeof(uint16_t) + sizeof(*rp) != length) {
			error("Incorrect packet size for index list response");
			return;
		}

		for (i = 0; i < num; i++) {
			uint16_t index;

			index = btohs(rp->index[i]);

			DBG("Found index %u", index);
			//Found index 0

			/*
			 * Pretend to be index added event notification.
			 *
			 * It is safe to just trigger the procedure for index
			 * added notification. It does check against itself.
			 */
			index_added(index, 0, NULL, NULL);
		}
	}

	error("Failed to read controller index list");
}

//使能扫描
g_dbus_proxy_call_sync(adapter_proxy, "StartDiscovery" ,NULL,G_DBUS_CALL_FLAGS_NONE,-1,NULL,&error)
	=>{ GDBUS_METHOD("StartDiscovery", NULL, NULL, start_discovery) } // src/adapter.c
static DBusMessage *start_discovery(DBusConnection *conn,
					DBusMessage *msg, void *user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct btd_adapter *adapter = user_data;
	const char *sender = dbus_message_get_sender(msg);
	struct watch_client *client;
	bool is_discovering;

	DBG("sender %s", sender);

	if (!(adapter->current_settings & MGMT_SETTING_POWERED))
		return btd_error_not_ready(msg);

	is_discovering = get_discovery_client(adapter, sender, &client);

	/*
	 * Every client can only start one discovery, if the client
	 * already started a discovery then return an error.
	 */
	if (is_discovering)
		return btd_error_busy(msg);

	/*
	 * If there was pre-set filter, just reconnect it to discovery_list,
	 * and trigger scan.
	 */
	if (client) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		adapter->set_filter_list = g_slist_remove(
					     adapter->set_filter_list, client);
		adapter->discovery_list = g_slist_prepend(
					      adapter->discovery_list, client);
		update_discovery_filter(adapter);
		return dbus_message_new_method_return(msg);
	}

	client = g_new0(struct watch_client, 1);

	client->adapter = adapter;
	client->owner = g_strdup(sender);
	client->discovery_filter = NULL;
	client->watch = g_dbus_add_disconnect_watch(dbus_conn, sender,
						discovery_disconnect, client,
						discovery_destroy);
	adapter->discovery_list = g_slist_prepend(adapter->discovery_list,
								client);

	/*
	 * Just trigger the discovery here. In case an already running
	 * discovery in idle phase exists, it will be restarted right
	 * away.
	 */
	update_discovery_filter(adapter);
	static void update_discovery_filter(struct btd_adapter *adapter)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct mgmt_cp_start_service_discovery *sd_cp;

		DBG("");

		if (discovery_filter_to_mgmt_cp(adapter, &sd_cp)) {
			btd_error(adapter->dev_id,
					"discovery_filter_to_mgmt_cp returned error");
			return;
		}
		static int discovery_filter_to_mgmt_cp(struct btd_adapter *adapter,
					   struct mgmt_cp_start_service_discovery **cp_ptr)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			GSList *uuids = NULL;
			struct mgmt_cp_start_service_discovery *cp;
			int rssi = DISTANCE_VAL_INVALID;
			int uuid_count;
			uint8_t discovery_type = 0;

			DBG("");

			if (merge_discovery_filters(adapter, &rssi, &discovery_type, &uuids)) {
				/* There are only regular scans, run just regular scan. */
				*cp_ptr = NULL;
				return 0;
			}

			uuid_count = g_slist_length(uuids);

			cp = g_try_malloc(sizeof(*cp) + 16*uuid_count);
			*cp_ptr = cp;
			if (!cp) {
				g_slist_free(uuids);
				return -1;
			}

			cp->type = discovery_type;
			cp->rssi = rssi;
			cp->uuid_count = uuid_count;
			populate_mgmt_filter_uuids(cp->uuids, uuids);

			g_slist_free(uuids);
			return 0;
		}

		/*
		 * If filters are equal, then don't update scan, except for when
		 * starting discovery.
		 */
		if (filters_equal(adapter->current_discovery_filter, sd_cp) &&
			adapter->discovering != 0) {
			DBG("filters were equal, deciding to not restart the scan.");
			g_free(sd_cp);
			return;
		}

		g_free(adapter->current_discovery_filter);
		adapter->current_discovery_filter = sd_cp;

		trigger_start_discovery(adapter, 0);
		static void trigger_start_discovery(struct btd_adapter *adapter, guint delay)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);

			DBG("");

			cancel_passive_scanning(adapter);

			if (adapter->discovery_idle_timeout > 0) {
				g_source_remove(adapter->discovery_idle_timeout);
				adapter->discovery_idle_timeout = 0;
			}

			/*
			 * If the controller got powered down in between, then ensure
			 * that we do not keep trying to restart discovery.
			 *
			 * This is safe-guard and should actually never trigger.
			 */
			if (!(adapter->current_settings & MGMT_SETTING_POWERED))
				return;

			adapter->discovery_idle_timeout = g_timeout_add_seconds(delay,
							start_discovery_timeout, adapter);
			static gboolean start_discovery_timeout(gpointer user_data)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct btd_adapter *adapter = user_data;
				struct mgmt_cp_start_service_discovery *sd_cp;
				uint8_t new_type;

				DBG("");

				adapter->discovery_idle_timeout = 0;

				/* If we're doing filtered discovery, it must be quickly restarted */
				adapter->no_scan_restart_delay = !!adapter->current_discovery_filter;

				DBG("adapter->current_discovery_filter == %d",
					!!adapter->current_discovery_filter);

				new_type = get_scan_type(adapter);

				if (adapter->discovery_enable == 0x01) {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct mgmt_cp_stop_discovery cp;

					/*
					 * If we're asked to start regular discovery, and there is an
					 * already running regular discovery and it has the same type,
					 * then just keep it.
					 */
					if (!adapter->current_discovery_filter &&
						!adapter->filtered_discovery &&
						adapter->discovery_type == new_type) {
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						if (adapter->discovering) {
							printf("jokerb %s:in %d.\n",__func__,__LINE__);
							return FALSE;
						}

						adapter->discovering = true;
						g_dbus_emit_property_changed(dbus_conn, adapter->path,
								ADAPTER_INTERFACE, "Discovering");
						return FALSE;
					}

					/*
					 * Otherwise the current discovery must be stopped. So
					 * queue up a stop discovery command.
					 *
					 * This can happen if a passive scanning for Low Energy
					 * devices is ongoing, or scan type is changed between
					 * regular and filtered, or filter was updated.
					 */
					cp.type = adapter->discovery_type;
					mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,
								adapter->dev_id, sizeof(cp), &cp,
								NULL, NULL, NULL);

					/* Don't even bother to try to quickly start discovery
					 * just after stopping it, it would fail with status
					 * MGMT_BUSY. Instead discovering_callback will take
					 * care of that.
					 */
					return FALSE;

				}

				/* Regular discovery is required */
				if (!adapter->current_discovery_filter) {
					printf("jokerb %s:in %d.\n",__func__,__LINE__); //
					struct mgmt_cp_start_discovery cp;

					cp.type = new_type;
					mgmt_send(adapter->mgmt, MGMT_OP_START_DISCOVERY,
							adapter->dev_id, sizeof(cp), &cp,
							start_discovery_complete, adapter, NULL);
					return FALSE;
					static void start_discovery_complete(uint8_t status, uint16_t length,
										const void *param, void *user_data)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						struct btd_adapter *adapter = user_data;
						const struct mgmt_cp_start_discovery *rp = param;

						DBG("status 0x%02x", status);

						if (length < sizeof(*rp)) {
							btd_error(adapter->dev_id,
								"Wrong size of start discovery return parameters");
							return;
						}

						if (status == MGMT_STATUS_SUCCESS) { //GM in here
							adapter->discovery_type = rp->type;
							adapter->discovery_enable = 0x01;

							if (adapter->current_discovery_filter)
								adapter->filtered_discovery = true;
							else
								adapter->filtered_discovery = false;

							if (adapter->discovering)
								return;

							adapter->discovering = true;
							g_dbus_emit_property_changed(dbus_conn, adapter->path,
										ADAPTER_INTERFACE, "Discovering");
							return;
						}

						/*
						 * In case the restart of the discovery failed, then just trigger
						 * it for the next idle timeout again.
						 */
						trigger_start_discovery(adapter, IDLE_DISCOV_TIMEOUT * 2);
					}
				}

				/* Filtered discovery is required */
				sd_cp = adapter->current_discovery_filter;

				DBG("sending MGMT_OP_START_SERVICE_DISCOVERY %d, %d, %d",
							sd_cp->rssi, sd_cp->type, sd_cp->uuid_count);

				mgmt_send(adapter->mgmt, MGMT_OP_START_SERVICE_DISCOVERY,
					  adapter->dev_id, sizeof(*sd_cp) + sd_cp->uuid_count * 16,
					  sd_cp, start_discovery_complete, adapter, NULL);

				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				return FALSE;
			}
		}
	}

	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	return dbus_message_new_method_return(msg);
}
discovering_callback
static void discovering_callback(uint16_t index, uint16_t length,
					const void *param, void *user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	const struct mgmt_ev_discovering *ev = param;
	struct btd_adapter *adapter = user_data;

	if (length < sizeof(*ev)) {
		btd_error(adapter->dev_id, "Too small discovering event");
		return;
	}

	DBG("hci%u type %u discovering %u method %d", adapter->dev_id, ev->type,
				ev->discovering, adapter->filtered_discovery);
	//hci0 type 7 discovering 1 method 0

	if (adapter->discovery_enable == ev->discovering) {
	printf("jokerb %s:in %d.\n",__func__,__LINE__); // GM: in here
		return;
	}

	adapter->discovery_type = ev->type;
	adapter->discovery_enable = ev->discovering;

	/*
	 * Check for existing discoveries triggered by client applications
	 * and ignore all others.
	 *
	 * If there are no clients, then it is good idea to trigger a
	 * passive scanning attempt.
	 */
	if (!adapter->discovery_list) {
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
		if (!adapter->connect_le) {
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
			trigger_passive_scanning(adapter);
		}
		return;
	}

	if (adapter->discovery_suspended) {
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
		return;
	}

	switch (adapter->discovery_enable) {
	case 0x00:
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
		if (adapter->no_scan_restart_delay) {
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
			trigger_start_discovery(adapter, 0);
		}
		else {
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
			trigger_start_discovery(adapter, IDLE_DISCOV_TIMEOUT);
		}
		break;

	case 0x01:
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
		if (adapter->discovery_idle_timeout > 0) {
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
			g_source_remove(adapter->discovery_idle_timeout);
			adapter->discovery_idle_timeout = 0;
		}

		break;
	}
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
}
device_found_callback
static void device_found_callback(uint16_t index, uint16_t length,
					const void *param, void *user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	const struct mgmt_ev_device_found *ev = param;
	struct btd_adapter *adapter = user_data;
	const uint8_t *eir;
	uint16_t eir_len;
	uint32_t flags;
	bool confirm_name;
	bool legacy;
	char addr[18];

	if (length < sizeof(*ev)) {
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
		btd_error(adapter->dev_id,
			"Too short device found event (%u bytes)", length);
		return;
	}

	eir_len = btohs(ev->eir_len);
	if (length != sizeof(*ev) + eir_len) {
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
		btd_error(adapter->dev_id,
				"Device found event size mismatch (%u != %zu)",
					length, sizeof(*ev) + eir_len);
		return;
	}

	if (eir_len == 0) {
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
		eir = NULL;
	}
	else {
	printf("jokerb %s:in %d.\n",__func__,__LINE__); //
		eir = ev->eir;
	}

	flags = btohl(ev->flags);

	ba2str(&ev->addr.bdaddr, addr);
	DBG("hci%u addr %s, rssi %d flags 0x%04x eir_len %u",
			index, addr, ev->rssi, flags, eir_len);
	//hci0 addr 3C:0C:1E:A7:89:11, rssi -80 flags 0x0004 eir_len 31

	confirm_name = (flags & MGMT_DEV_FOUND_CONFIRM_NAME);
	legacy = (flags & MGMT_DEV_FOUND_LEGACY_PAIRING);

	update_found_devices(adapter, &ev->addr.bdaddr, ev->addr.type,
					ev->rssi, confirm_name, legacy,
					flags & MGMT_DEV_FOUND_NOT_CONNECTABLE,
					eir, eir_len);
	static void update_found_devices(struct btd_adapter *adapter,
						const bdaddr_t *bdaddr,
						uint8_t bdaddr_type, int8_t rssi,
						bool confirm, bool legacy,
						bool not_connectable,
						const uint8_t *data, uint8_t data_len)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct btd_device *dev;
		struct eir_data eir_data;
		bool name_known, discoverable;
		char addr[18];
		bool duplicate = false;

		memset(&eir_data, 0, sizeof(eir_data));
		eir_parse(&eir_data, data, data_len);

		if (bdaddr_type == BDADDR_BREDR || adapter->filtered_discovery) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			discoverable = true;
		}
		else {
			printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			discoverable = eir_data.flags & (EIR_LIM_DISC | EIR_GEN_DISC);
		}

		ba2str(bdaddr, addr);

		dev = btd_adapter_find_device(adapter, bdaddr, bdaddr_type);
		if (!dev) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			/*
			 * If no client has requested discovery or the device is
			 * not marked as discoverable, then do not create new
			 * device objects.
			 */
			if (!adapter->discovery_list || !discoverable) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				eir_data_free(&eir_data);
				return;
			}

			dev = adapter_create_device(adapter, bdaddr, bdaddr_type);
			static struct btd_device *adapter_create_device(struct btd_adapter *adapter,
									const bdaddr_t *bdaddr,
									uint8_t bdaddr_type)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct btd_device *device;

				device = device_create(adapter, bdaddr, bdaddr_type); <tag56>
				if (!device)
					return NULL;
				struct btd_device *device_create(struct btd_adapter *adapter,
								const bdaddr_t *bdaddr, uint8_t bdaddr_type)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct btd_device *device;
					const bdaddr_t *sba;
					char src[18], dst[18];
					char *str;

					ba2str(bdaddr, dst);
					DBG("dst %s", dst);

					device = device_new(adapter, dst);
					if (device == NULL)
						return NULL;
					static struct btd_device *device_new(struct btd_adapter *adapter,
									const char *address)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						char *address_up;
						struct btd_device *device;
						const char *adapter_path = adapter_get_path(adapter);

						DBG("address %s", address);

						device = g_try_malloc0(sizeof(struct btd_device));
						if (device == NULL)
							return NULL;

						device->tx_power = 127;

						device->db = gatt_db_new();
						if (!device->db) {
							g_free(device);
							return NULL;
						}

						memset(device->ad_flags, INVALID_FLAGS, sizeof(device->ad_flags));

						device->ad = bt_ad_new();
						if (!device->ad) {
							device_free(device);
							return NULL;
						}

						address_up = g_ascii_strup(address, -1);
						device->path = g_strdup_printf("%s/dev_%s", adapter_path, address_up);
						g_strdelimit(device->path, ":", '_');
						g_free(address_up);

						str2ba(address, &device->bdaddr); <tag59>

						device->client_dbus = btd_gatt_client_new(device);
						if (!device->client_dbus) {
							error("Failed to create btd_gatt_client");
							device_free(device);
							return NULL;
						}

						DBG("Creating device %s", device->path);

						if (g_dbus_register_interface(dbus_conn,
										device->path, DEVICE_INTERFACE,
										device_methods, NULL,
										device_properties, device,
										device_free) == FALSE) {
							error("Unable to register device interface for %s", address);
							device_free(device);
							return NULL;
						}

						device->adapter = adapter; <tag60>
						device->temporary = true; <tag61>

						device->db_id = gatt_db_register(device->db, gatt_service_added,
										gatt_service_removed, device, NULL);

						return btd_device_ref(device);
					}

					device->bdaddr_type = bdaddr_type; <tag57>

					if (bdaddr_type == BDADDR_BREDR)
						device->bredr = true; <tag58>
					else
						device->le = true;

					sba = btd_adapter_get_address(adapter);
					ba2str(sba, src);

					str = load_cached_name(device, src, dst);
					if (str) {
						strcpy(device->name, str);
						g_free(str);
					}

					return device;
				}

				adapter->devices = g_slist_append(adapter->devices, device); <tag65>

				return device;
			}
		}

		if (!dev) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			btd_error(adapter->dev_id,
				"Unable to create object for found device %s", addr);
			eir_data_free(&eir_data);
			return;
		}

		device_update_last_seen(dev, bdaddr_type);
		void device_update_last_seen(struct btd_device *device, uint8_t bdaddr_type)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			if (bdaddr_type == BDADDR_BREDR)
				device->bredr_seen = time(NULL);
			else
				device->le_seen = time(NULL);
		}

		/*
		 * FIXME: We need to check for non-zero flags first because
		 * older kernels send separate adv_ind and scan_rsp. Newer
		 * kernels send them merged, so once we know which mgmt version
		 * supports this we can make the non-zero check conditional.
		 */
		if (bdaddr_type != BDADDR_BREDR && eir_data.flags &&
						!(eir_data.flags & EIR_BREDR_UNSUP)) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			device_set_bredr_support(dev);
			/* Update last seen for BR/EDR in case its flag is set */
			device_update_last_seen(dev, BDADDR_BREDR);
		}

		if (eir_data.name != NULL && eir_data.name_complete) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			device_store_cached_name(dev, eir_data.name);
			void device_store_cached_name(struct btd_device *dev, const char *name)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				char filename[PATH_MAX];
				char s_addr[18], d_addr[18];
				GKeyFile *key_file;
				char *data;
				gsize length = 0;

				if (device_address_is_private(dev)) {
					warn("Can't store name for private addressed device %s",
											dev->path);
					return;
				}

				ba2str(btd_adapter_get_address(dev->adapter), s_addr);
				ba2str(&dev->bdaddr, d_addr);
				snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", s_addr, d_addr);
				create_file(filename, S_IRUSR | S_IWUSR);
				printf("jokerb %s:in %d.filename %s\n",__func__,__LINE__, filename);
				//filename /userdata/lib/bluetooth/68:89:5B:01:28:23/cache/C0:ED:E5:01:68:A2

				key_file = g_key_file_new();
				g_key_file_load_from_file(key_file, filename, 0, NULL);
				g_key_file_set_string(key_file, "General", "Name", name);

				data = g_key_file_to_data(key_file, &length, NULL);
				g_file_set_contents(filename, data, length, NULL);
				g_free(data);

				g_key_file_free(key_file);
			}
		}

		/*
		 * Only skip devices that are not connected, are temporary and there
		 * is no active discovery session ongoing.
		 */
		if (!btd_device_is_connected(dev) && (device_is_temporary(dev) &&
							 !adapter->discovery_list)) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			eir_data_free(&eir_data);
			return;
		}
		bool btd_device_is_connected(struct btd_device *dev)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			return dev->bredr_state.connected || dev->le_state.connected;
		}

		if (adapter->filtered_discovery &&
			!is_filter_match(adapter->discovery_list, &eir_data, rssi)) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			eir_data_free(&eir_data);
			return;
		}
		static bool is_filter_match(GSList *discovery_filter, struct eir_data *eir_data,
										int8_t rssi)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			GSList *l, *m;
			bool got_match = false;

			for (l = discovery_filter; l != NULL && got_match != true;
									l = g_slist_next(l)) {
				struct watch_client *client = l->data;
				struct discovery_filter *item = client->discovery_filter;

				/*
				 * If one of currently running scans is regular scan, then
				 * return all devices as matches
				 */
				if (!item) {
					got_match = true;
					continue;
				}

				/* if someone started discovery with empty uuids, he wants all
				 * devices in given proximity.
				 */
				if (!item->uuids)
					got_match = true;
				else {
					for (m = item->uuids; m != NULL && got_match != true;
									m = g_slist_next(m)) {
						/* m->data contains string representation of
						 * uuid.
						 */
						if (g_slist_find_custom(eir_data->services,
									m->data,
									g_strcmp) != NULL)
							got_match = true;
					}
				}

				if (got_match) {
					/* we have service match, check proximity */
					if (item->rssi == DISTANCE_VAL_INVALID ||
						item->rssi <= rssi ||
						item->pathloss == DISTANCE_VAL_INVALID ||
						(eir_data->tx_power != 127 &&
						 eir_data->tx_power - rssi <= item->pathloss))
						return true;

					got_match = false;
				}
			}

			return got_match;
		}

		device_set_legacy(dev, legacy);
		void device_set_legacy(struct btd_device *device, bool legacy)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			if (!device) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
				return;
			}

			DBG("legacy %d", legacy);

			if (device->legacy == legacy) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__); // GM in here
				return;
			}

			device->legacy = legacy;

			g_dbus_emit_property_changed(dbus_conn, device->path,
							DEVICE_INTERFACE, "LegacyPairing");
		}

		if (adapter->filtered_discovery) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			device_set_rssi_with_delta(dev, rssi, 0);
		}
		else {
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			device_set_rssi(dev, rssi);
			void device_set_rssi(struct btd_device *device, int8_t rssi)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				device_set_rssi_with_delta(device, rssi, RSSI_THRESHOLD);
				void device_set_rssi_with_delta(struct btd_device *device, int8_t rssi,
											int8_t delta_threshold)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					if (!device)
						return;

					if (rssi == 0 || device->rssi == 0) {
					printf("jokerb %s:in %d.\n",__func__,__LINE__); //
						if (device->rssi == rssi) {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
							return;
						}

						DBG("rssi %d", rssi);
						//rssi -86

						device->rssi = rssi; <tag68>
					} else {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
						int delta;

						if (device->rssi > rssi) {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
							delta = device->rssi - rssi;
						}
						else {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
							delta = rssi - device->rssi;
						}

						/* only report changes of delta_threshold dBm or more */
						if (delta < delta_threshold) {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
							return;
						}

						DBG("rssi %d delta %d", rssi, delta);

						device->rssi = rssi;
					}

					g_dbus_emit_property_changed(dbus_conn, device->path,
										DEVICE_INTERFACE, "RSSI");
					printf("jokerb %s:in %d.\n",__func__,__LINE__);//
				}
			}
		}

		if (eir_data.tx_power != 127) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			device_set_tx_power(dev, eir_data.tx_power);
		}

		if (eir_data.appearance != 0) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			device_set_appearance(dev, eir_data.appearance);
		}

		/* Report an unknown name to the kernel even if there is a short name
		 * known, but still update the name with the known short name. */
		name_known = device_name_known(dev);
		bool device_name_known(struct btd_device *device)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			return device->name[0] != '\0';
		}

		if (eir_data.name && (eir_data.name_complete || !name_known)) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			btd_device_device_set_name(dev, eir_data.name);
			void btd_device_device_set_name(struct btd_device *device, const char *name)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				if (strncmp(name, device->name, MAX_NAME_LENGTH) == 0) {
					return; //GM in here
				}

				DBG("%s %s", device->path, name);

				strncpy(device->name, name, MAX_NAME_LENGTH);

				store_device_info(device);
				static void store_device_info(struct btd_device *device)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					if (device->temporary || device->store_id > 0)
						return;

					if (device_address_is_private(device)) {
						warn("Can't store info for private addressed device %s",
												device->path);
						return;
					}

					device->store_id = g_idle_add(store_device_info_cb, device);
				}

				g_dbus_emit_property_changed(dbus_conn, device->path,
									DEVICE_INTERFACE, "Name");

				if (device->alias != NULL)
					return;

				g_dbus_emit_property_changed(dbus_conn, device->path,
									DEVICE_INTERFACE, "Alias");
			}
		}

		if (eir_data.class != 0) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			device_set_class(dev, eir_data.class);
		}

		if (eir_data.did_source || eir_data.did_vendor ||
				eir_data.did_product || eir_data.did_version) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			btd_device_set_pnpid(dev, eir_data.did_source,
								eir_data.did_vendor,
								eir_data.did_product,
								eir_data.did_version);
		}

		device_add_eir_uuids(dev, eir_data.services);
		void device_add_eir_uuids(struct btd_device *dev, GSList *uuids)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			GSList *l;
			bool added = false;

			if (dev->bredr_state.svc_resolved || dev->le_state.svc_resolved)
				return;

			for (l = uuids; l != NULL; l = l->next) {
				const char *str = l->data;
				if (g_slist_find_custom(dev->eir_uuids, str, bt_uuid_strcmp))
					continue;
				added = true;
				dev->eir_uuids = g_slist_append(dev->eir_uuids, g_strdup(str)); <tag70>
			}

			if (added)
				g_dbus_emit_property_changed(dbus_conn, dev->path,
								DEVICE_INTERFACE, "UUIDs");
		}

		if (adapter->discovery_list) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			g_slist_foreach(adapter->discovery_list, filter_duplicate_data,
									&duplicate);
		}

		if (eir_data.msd_list) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			device_set_manufacturer_data(dev, eir_data.msd_list, duplicate);
			void device_set_manufacturer_data(struct btd_device *dev, GSList *list,
											bool duplicate)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				if (duplicate)
					bt_ad_clear_manufacturer_data(dev->ad);

				g_slist_foreach(list, add_manufacturer_data, dev);
				static void add_manufacturer_data(void *data, void *user_data)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct eir_msd *msd = data;
					struct btd_device *dev = user_data;

					if (!bt_ad_add_manufacturer_data(dev->ad, msd->company, msd->data,
												msd->data_len))
						return;

					g_dbus_emit_property_changed(dbus_conn, dev->path,
									DEVICE_INTERFACE, "ManufacturerData");
				}
			}
			adapter_msd_notify(adapter, dev, eir_data.msd_list);
		}

		if (eir_data.sd_list) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			device_set_service_data(dev, eir_data.sd_list, duplicate);
		}

		if (bdaddr_type != BDADDR_BREDR) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			device_set_flags(dev, eir_data.flags);
			void device_set_flags(struct btd_device *device, uint8_t flags)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				if (!device)
					return;

				DBG("flags %d", flags);

				if (device->ad_flags[0] == flags)
					return;

				device->ad_flags[0] = flags;

				g_dbus_emit_property_changed(dbus_conn, device->path,
								DEVICE_INTERFACE, "AdvertisingFlags");
			}
		}

		eir_data_free(&eir_data);

		/*
		 * Only if at least one client has requested discovery, maintain
		 * list of found devices and name confirming for legacy devices.
		 * Otherwise, this is an event from passive discovery and we
		 * should check if the device needs connecting to.
		 */
		if (!adapter->discovery_list) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			goto connect_le;
		}

		if (g_slist_find(adapter->discovery_found, dev)) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			return;
		}

		if (confirm) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			confirm_name(adapter, bdaddr, bdaddr_type, name_known);
		}

		adapter->discovery_found = g_slist_prepend(adapter->discovery_found,
										dev);

		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
		return;

	connect_le:
		/* Ignore non-connectable events */
		if (not_connectable) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			return;
		}

		/*
		 * If we're in the process of stopping passive scanning and
		 * connecting another (or maybe even the same) LE device just
		 * ignore this one.
		 */
		if (adapter->connect_le)
			return;

		/*
		 * If kernel background scan is used then the kernel is
		 * responsible for connecting.
		 */
		if (kernel_conn_control)
			return;

		/*
		 * If this is an LE device that's not connected and part of the
		 * connect_list stop passive scanning so that a connection
		 * attempt to it can be made
		 */
		if (bdaddr_type != BDADDR_BREDR && !btd_device_is_connected(dev) &&
					g_slist_find(adapter->connect_list, dev)) {
			adapter->connect_le = dev;
			stop_passive_scanning(adapter);
		}
	}
	printf("jokerb %s:in %d.\n",__func__,__LINE__); //
}

//配对 经典蓝牙设备
g_dbus_proxy_call_sync(adapter_proxy, "Pair" ,NULL,G_DBUS_CALL_FLAGS_NONE,-1,NULL,&error)
	=>{ GDBUS_ASYNC_METHOD("Pair", NULL, NULL, pair_device) } // src/device.c
static DBusMessage *pair_device(DBusConnection *conn, DBusMessage *msg,void *data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct btd_device *device = data;
	struct btd_adapter *adapter = device->adapter;
	struct bearer_state *state;
	uint8_t bdaddr_type;
	const char *sender;
	struct agent *agent;
	struct bonding_req *bonding;
	uint8_t io_cap;
	int err;

    DBG("");
	btd_device_set_temporary(device, false);
	void btd_device_set_temporary(struct btd_device *device, bool temporary)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		DBG("");
		if (!device) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			return;
		}

		if (device->temporary == temporary) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			return;
		}

		if (device_address_is_private(device)) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			return;
		}

		DBG("temporary %d", temporary);
		//temporary 0

		device->temporary = temporary;

		if (temporary) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			if (device->bredr) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
				adapter_whitelist_remove(device->adapter, device);
			}
			adapter_connect_list_remove(device->adapter, device);
			return;
		}

		if (device->bredr) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			adapter_whitelist_add(device->adapter, device);
			void adapter_whitelist_add(struct btd_adapter *adapter, struct btd_device *dev)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct mgmt_cp_add_device cp;

				if (!kernel_conn_control)
					return;

				memset(&cp, 0, sizeof(cp));
				bacpy(&cp.addr.bdaddr, device_get_address(dev));
				cp.addr.type = BDADDR_BREDR;
				cp.action = 0x01;

				mgmt_send(adapter->mgmt, MGMT_OP_ADD_DEVICE,
							adapter->dev_id, sizeof(cp), &cp,
							add_whitelist_complete, adapter, NULL);
			}
		}

		store_device_info(device);
		static void store_device_info(struct btd_device *device)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			if (device->temporary || device->store_id > 0)
				return;

			if (device_address_is_private(device)) {
				warn("Can't store info for private addressed device %s",
										device->path);
				return;
			}
			static bool device_address_is_private(struct btd_device *dev)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				if (dev->bdaddr_type != BDADDR_LE_RANDOM)
					return false;

				switch (dev->bdaddr.b[5] >> 6) {
				case 0x00:	/* Private non-resolvable */
				case 0x01:	/* Private resolvable */
					return true;
				default:
					return false;
				}
			}

			device->store_id = g_idle_add(store_device_info_cb, device);
		}
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
	}

	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INVALID))
		return btd_error_invalid_args(msg);

	if (device->bonding)
		return btd_error_in_progress(msg);

	if (device->bredr_state.bonded)
		bdaddr_type = device->bdaddr_type;
	else if (device->le_state.bonded)
		bdaddr_type = BDADDR_BREDR;
	else
		bdaddr_type = select_conn_bearer(device);

	state = get_state(device, bdaddr_type);
	static struct bearer_state *get_state(struct btd_device *dev,
								uint8_t bdaddr_type)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		if (bdaddr_type == BDADDR_BREDR)
			return &dev->bredr_state;
		else
			return &dev->le_state;
	}

	if (state->bonded)
		return btd_error_already_exists(msg);

	sender = dbus_message_get_sender(msg);

	agent = agent_get(sender);
	if (agent) {
		io_cap = agent_get_io_capability(agent);
        DBG("get io capability from agent\n");  //GM in here
    }
	else {
		//io_cap = IO_CAPABILITY_NOINPUTNOOUTPUT;
		io_cap = IO_CAPABILITY_DISPLAYYESNO;
        DBG("set io capability  agent to displayYesNo\n"); 
    }

	bonding = bonding_request_new(msg, device, bdaddr_type, agent);
	static struct bonding_req *bonding_request_new(DBusMessage *msg,
							struct btd_device *device,
							uint8_t bdaddr_type,
							struct agent *agent)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct bonding_req *bonding;
		char addr[18];

		ba2str(&device->bdaddr, addr);
		DBG("Requesting bonding for %s", addr);

		bonding = g_new0(struct bonding_req, 1);

		bonding->msg = dbus_message_ref(msg);
		bonding->bdaddr_type = bdaddr_type;

		bonding->cb_iter = btd_adapter_pin_cb_iter_new(device->adapter);
		struct btd_adapter_pin_cb_iter *btd_adapter_pin_cb_iter_new(
								struct btd_adapter *adapter)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			struct btd_adapter_pin_cb_iter *iter =
						g_new0(struct btd_adapter_pin_cb_iter, 1);

			iter->it = adapter->pin_callbacks;
			iter->attempt = 1;

			return iter;
		}

		/* Marks the bonding start time for the first attempt on request
		 * construction. The following attempts will be updated on
		 * device_bonding_retry. */
		clock_gettime(CLOCK_MONOTONIC, &bonding->attempt_start_time);

		if (agent)
			bonding->agent = agent_ref(agent);

		return bonding;
	}

	if (agent)
		agent_unref(agent);

	bonding->listener_id = g_dbus_add_disconnect_watch(dbus_conn,
						sender, create_bond_req_exit,
						device, NULL);

	device->bonding = bonding;
	bonding->device = device;

	/* Due to a bug in the kernel we might loose out on ATT commands
	 * that arrive during the SMP procedure, so connect the ATT
	 * channel first and only then start pairing (there's code for
	 * this in the ATT connect callback)
	 */
	if (bdaddr_type != BDADDR_BREDR) {
		if (!state->connected && btd_le_connect_before_pairing())
			err = device_connect_le(device);
		else
			err = adapter_create_bonding(adapter, &device->bdaddr,
							device->bdaddr_type,
							io_cap);
	} else {
		err = adapter_create_bonding(adapter, &device->bdaddr, BDADDR_BREDR, io_cap);
		int adapter_create_bonding(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
							uint8_t addr_type, uint8_t io_cap)
		{
			if (adapter->pair_device_id > 0) {
				btd_error(adapter->dev_id,
					"Unable pair since another pairing is in progress");
				return -EBUSY;
			}

			suspend_discovery(adapter);
			static void suspend_discovery(struct btd_adapter *adapter)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct mgmt_cp_stop_discovery cp;

				DBG("");

				adapter->discovery_suspended = true;

				/*
				 * If there are no clients discovering right now, then there is
				 * also nothing to suspend.
				 */
				if (!adapter->discovery_list)
					return;

				/*
				 * In case of being inside the idle phase, make sure to remove
				 * the timeout to not trigger a restart.
				 *
				 * The restart will be triggered when the discovery is resumed.
				 */
				if (adapter->discovery_idle_timeout > 0) {
					g_source_remove(adapter->discovery_idle_timeout);
					adapter->discovery_idle_timeout = 0;
				}

				if (adapter->discovery_enable == 0x00)
					return;

				cp.type = adapter->discovery_type;

				mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,
							adapter->dev_id, sizeof(cp), &cp,
							suspend_discovery_complete, adapter, NULL);
			}

			return adapter_bonding_attempt(adapter, bdaddr, addr_type, io_cap);
			int adapter_bonding_attempt(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
								uint8_t addr_type, uint8_t io_cap)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct mgmt_cp_pair_device cp;
				char addr[18];
				struct pair_device_data *data;
				unsigned int id;

				ba2str(bdaddr, addr);
				DBG("hci%u bdaddr %s type %d io_cap 0x%02x",
							adapter->dev_id, addr, addr_type, io_cap);
				//hci0 bdaddr 04:57:91:CC:BB:0E type 0 io_cap 0x01

				/* Reset the pincode_requested flag for a new bonding attempt. */
				adapter->pincode_requested = false;

				memset(&cp, 0, sizeof(cp));
				bacpy(&cp.addr.bdaddr, bdaddr);
				cp.addr.type = addr_type;
				cp.io_cap = io_cap;

				data = g_new0(struct pair_device_data, 1);
				data->adapter = adapter;
				bacpy(&data->bdaddr, bdaddr);
				data->addr_type = addr_type;

				id = mgmt_send(adapter->mgmt, MGMT_OP_PAIR_DEVICE,
							adapter->dev_id, sizeof(cp), &cp,
							pair_device_complete, data,
							free_pair_device_data);

				if (id == 0) {
					btd_error(adapter->dev_id, "Failed to pair %s for hci%u",
										addr, adapter->dev_id);
					free_pair_device_data(data);
					return -EIO;
				}

				adapter->pair_device_id = id;

				/* Due to a bug in the kernel it is possible that a LE pairing
				 * request never times out. Therefore, add a timer to clean up
				 * if no response arrives
				 */
				adapter->pair_device_timeout = g_timeout_add_seconds(BONDING_TIMEOUT,
									pair_device_timeout, data);

				return 0;
			}
		}
	}

    DBG("adapter_create_bonding return: %d\n", err);
	if (err < 0) {
		bonding_request_free(device->bonding);
		return btd_error_failed(msg, strerror(-err));
	}

    DBG("return\n");
	return NULL;
}

add_whitelist_complete
static void add_whitelist_complete(uint8_t status, uint16_t length,
					const void *param, void *user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	const struct mgmt_rp_add_device *rp = param;
	struct btd_adapter *adapter = user_data;
	struct btd_device *dev;
	char addr[18];

	if (length < sizeof(*rp)) {
		btd_error(adapter->dev_id,
				"Too small Add Device complete event");
		return;
	}

	ba2str(&rp->addr.bdaddr, addr);

	dev = btd_adapter_find_device(adapter, &rp->addr.bdaddr,rp->addr.type);
	struct btd_device *btd_adapter_find_device(struct btd_adapter *adapter,
								const bdaddr_t *dst,
								uint8_t bdaddr_type)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct device_addr_type addr;
		struct btd_device *device;
		GSList *list;

		if (!adapter) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			return NULL;
		}

		bacpy(&addr.bdaddr, dst);
		addr.bdaddr_type = bdaddr_type;

		list = g_slist_find_custom(adapter->devices, &addr,
								device_addr_type_cmp);
		if (!list) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			return NULL;
		}

		device = list->data;

		/*
		 * If we're looking up based on public address and the address
		 * was not previously used over this bearer we may need to
		 * update LE or BR/EDR support information.
		 */
		if (bdaddr_type == BDADDR_BREDR) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			device_set_bredr_support(device);
			void device_set_bredr_support(struct btd_device *device)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				if (device->bredr)
					return;

				device->bredr = true;
				store_device_info(device);
				static void store_device_info(struct btd_device *device)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					if (device->temporary || device->store_id > 0)
						return;

					if (device_address_is_private(device)) {
						warn("Can't store info for private addressed device %s",
												device->path);
						return;
					}

					/* GM: 加将蓝牙设备信息写入/userdata/lib/xxx/设备地址/info 文件内. */
					device->store_id = g_idle_add(store_device_info_cb, device);
					static gboolean store_device_info_cb(gpointer user_data)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						struct btd_device *device = user_data;
						GKeyFile *key_file;
						char filename[PATH_MAX];
						char adapter_addr[18];
						char device_addr[18];
						char *str;
						char class[9];
						char **uuids = NULL;
						gsize length = 0;

						device->store_id = 0;

						ba2str(btd_adapter_get_address(device->adapter), adapter_addr);
						ba2str(&device->bdaddr, device_addr);
						snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
								device_addr);

						key_file = g_key_file_new();
						g_key_file_load_from_file(key_file, filename, 0, NULL);

						g_key_file_set_string(key_file, "General", "Name", device->name);

						if (device->alias != NULL)
							g_key_file_set_string(key_file, "General", "Alias",
													device->alias);
						else
							g_key_file_remove_key(key_file, "General", "Alias", NULL);

						if (device->class) {
							sprintf(class, "0x%6.6x", device->class);
							g_key_file_set_string(key_file, "General", "Class", class);
						} else {
							g_key_file_remove_key(key_file, "General", "Class", NULL);
						}

						if (device->appearance) {
							sprintf(class, "0x%4.4x", device->appearance);
							g_key_file_set_string(key_file, "General", "Appearance", class);
						} else {
							g_key_file_remove_key(key_file, "General", "Appearance", NULL);
						}

						update_technologies(key_file, device);

						g_key_file_set_boolean(key_file, "General", "Trusted",
												device->trusted);

						g_key_file_set_boolean(key_file, "General", "Blocked",
												device->blocked);

						if (device->uuids) {
							GSList *l;
							int i;

							uuids = g_new0(char *, g_slist_length(device->uuids) + 1);
							for (i = 0, l = device->uuids; l; l = g_slist_next(l), i++)
								uuids[i] = l->data;
							g_key_file_set_string_list(key_file, "General", "Services",
											(const char **)uuids, i);
						} else {
							g_key_file_remove_key(key_file, "General", "Services", NULL);
						}

						if (device->vendor_src) {
							g_key_file_set_integer(key_file, "DeviceID", "Source",
										device->vendor_src);
							g_key_file_set_integer(key_file, "DeviceID", "Vendor",
										device->vendor);
							g_key_file_set_integer(key_file, "DeviceID", "Product",
										device->product);
							g_key_file_set_integer(key_file, "DeviceID", "Version",
										device->version);
						} else {
							g_key_file_remove_group(key_file, "DeviceID", NULL);
						}

						if (device->local_csrk)
							store_csrk(device->local_csrk, key_file, "LocalSignatureKey");

						if (device->remote_csrk)
							store_csrk(device->remote_csrk, key_file, "RemoteSignatureKey");

						create_file(filename, S_IRUSR | S_IWUSR);

						str = g_key_file_to_data(key_file, &length, NULL);
						g_file_set_contents(filename, str, length, NULL);
						g_free(str);

						g_key_file_free(key_file);
						g_free(uuids);

						return FALSE;
					}
				}
			}
		}
		else {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			device_set_le_support(device, bdaddr_type);
		}

		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
		return device;
	}

	if (!dev) {
		btd_error(adapter->dev_id,
			"Add Device complete for unknown device %s", addr);
		return;
	}

	if (status != MGMT_STATUS_SUCCESS) {
		btd_error(adapter->dev_id,
					"Failed to add device %s: %s (0x%02x)",
					addr, mgmt_errstr(status), status);
		return;
	}

	DBG("%s added to kernel whitelist", addr);
	//04:57:91:CC:BB:0E added to kernel whitelist
}

//GM: 执行完add_whitelist_complete(), 就忽然执行这个函数了
static void connected_callback(uint16_t index, uint16_t length,
					const void *param, void *user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	const struct mgmt_ev_device_connected *ev = param;
	struct btd_adapter *adapter = user_data;
	struct btd_device *device;
	struct eir_data eir_data;
	uint16_t eir_len;
	char addr[18];
	bool name_known;

	if (length < sizeof(*ev)) {
		btd_error(adapter->dev_id, "Too small device connected event");
		return;
	}

	eir_len = btohs(ev->eir_len);
	if (length < sizeof(*ev) + eir_len) {
		btd_error(adapter->dev_id, "Too small device connected event");
		return;
	}

	ba2str(&ev->addr.bdaddr, addr);

	DBG("hci%u device %s connected eir_len %u", index, addr, eir_len);
	//hci0 device 04:57:91:CC:BB:0E connected eir_len 15

	device = btd_adapter_get_device(adapter, &ev->addr.bdaddr, ev->addr.type);
	if (!device) {
		btd_error(adapter->dev_id,
				"Unable to get device object for %s", addr);
		return;
	}
	struct btd_device *btd_adapter_get_device(struct btd_adapter *adapter,
						const bdaddr_t *addr,
						uint8_t addr_type)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct btd_device *device;

		if (!adapter) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			return NULL;
		}

		device = btd_adapter_find_device(adapter, addr, addr_type);
		if (device) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			return device;
		}
		struct btd_device *btd_adapter_find_device(struct btd_adapter *adapter,
									const bdaddr_t *dst,
									uint8_t bdaddr_type)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			struct device_addr_type addr;
			struct btd_device *device;
			GSList *list;

			if (!adapter) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
				return NULL;
			}

			bacpy(&addr.bdaddr, dst);
			addr.bdaddr_type = bdaddr_type;

			list = g_slist_find_custom(adapter->devices, &addr,
									device_addr_type_cmp);
			if (!list) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
				return NULL;
			}

			device = list->data;

			/*
			 * If we're looking up based on public address and the address
			 * was not previously used over this bearer we may need to
			 * update LE or BR/EDR support information.
			 */
			if (bdaddr_type == BDADDR_BREDR) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__); //
				device_set_bredr_support(device);
				void device_set_bredr_support(struct btd_device *device)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					if (device->bredr) // GM in here
						return;

					device->bredr = true;
					store_device_info(device);
				}
			}
			else {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
				device_set_le_support(device, bdaddr_type);
			}

			printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			return device;
		}

		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		return adapter_create_device(adapter, addr, addr_type); //GM: return before. no exec
	}

	memset(&eir_data, 0, sizeof(eir_data));
	if (eir_len > 0) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
		eir_parse(&eir_data, ev->eir, eir_len);
	}

	if (eir_data.class != 0) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
		device_set_class(device, eir_data.class);
		void device_set_class(struct btd_device *device, uint32_t class)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			if (device->class == class) // GM in here
				return;

			DBG("%s 0x%06X", device->path, class);

			device->class = class;

			store_device_info(device);

			g_dbus_emit_property_changed(dbus_conn, device->path,
								DEVICE_INTERFACE, "Class");
			g_dbus_emit_property_changed(dbus_conn, device->path,
								DEVICE_INTERFACE, "Icon");
		}
	}

	adapter_add_connection(adapter, device, ev->addr.type);
	static void adapter_add_connection(struct btd_adapter *adapter,
							struct btd_device *device,
							uint8_t bdaddr_type)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		device_add_connection(device, bdaddr_type);
		void device_add_connection(struct btd_device *dev, uint8_t bdaddr_type)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			struct bearer_state *state = get_state(dev, bdaddr_type);
			static struct bearer_state *get_state(struct btd_device *dev,
										uint8_t bdaddr_type)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				if (bdaddr_type == BDADDR_BREDR)
					return &dev->bredr_state;
				else
					return &dev->le_state;
			}

			device_update_last_seen(dev, bdaddr_type);
			void device_update_last_seen(struct btd_device *device, uint8_t bdaddr_type)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				if (bdaddr_type == BDADDR_BREDR)
					device->bredr_seen = time(NULL);
				else
					device->le_seen = time(NULL);
			}

			if (state->connected) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				char addr[18];
				ba2str(&dev->bdaddr, addr);
				error("Device %s is already connected", addr);
				return;
			}

			bacpy(&dev->conn_bdaddr, &dev->bdaddr);
			dev->conn_bdaddr_type = dev->bdaddr_type;

			/* If this is the first connection over this bearer */
			if (bdaddr_type == BDADDR_BREDR) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__); //
				device_set_bredr_support(dev); // GM in here
				void device_set_bredr_support(struct btd_device *device)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					if (device->bredr) { // GM in here
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
						return;
					}

					device->bredr = true;
					store_device_info(device);
					static void store_device_info(struct btd_device *device)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						if (device->temporary || device->store_id > 0)
							return;

						if (device_address_is_private(device)) {
							warn("Can't store info for private addressed device %s",
													device->path);
							return;
						}

						device->store_id = g_idle_add(store_device_info_cb, device);
					}
				}
			}
			else {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
				device_set_le_support(dev, bdaddr_type);
			}

			state->connected = true;

			if (dev->le_state.connected && dev->bredr_state.connected) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
				return;
			}

			g_dbus_emit_property_changed(dbus_conn, dev->path, DEVICE_INTERFACE,
										"Connected");
			printf("jokerb %s:in %d.\n",__func__,__LINE__); //
		}

		if (g_slist_find(adapter->connections, device)) {
			btd_error(adapter->dev_id,
					"Device is already marked as connected");
			return;
		}

		adapter->connections = g_slist_append(adapter->connections, device); <tag66>
	}

	name_known = device_name_known(device);
	bool device_name_known(struct btd_device *device)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		return device->name[0] != '\0';
	}

	if (eir_data.name && (eir_data.name_complete || !name_known)) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
		device_store_cached_name(device, eir_data.name);
		void device_store_cached_name(struct btd_device *dev, const char *name)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			char filename[PATH_MAX];
			char s_addr[18], d_addr[18];
			GKeyFile *key_file;
			char *data;
			gsize length = 0;

			if (device_address_is_private(dev)) {
				warn("Can't store name for private addressed device %s",
										dev->path);
				return;
			}

			ba2str(btd_adapter_get_address(dev->adapter), s_addr);
			ba2str(&dev->bdaddr, d_addr);
			snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", s_addr, d_addr);
			create_file(filename, S_IRUSR | S_IWUSR);
			printf("jokerb %s:in %d.filename %s\n",__func__,__LINE__, filename);
			///userdata/lib/bluetooth/68:89:5B:01:28:23/cache/04:57:91:CC:BB:0E

			key_file = g_key_file_new();
			g_key_file_load_from_file(key_file, filename, 0, NULL);
			g_key_file_set_string(key_file, "General", "Name", name);

			data = g_key_file_to_data(key_file, &length, NULL);
			g_file_set_contents(filename, data, length, NULL);
			g_free(data);

			g_key_file_free(key_file);
		}
		btd_device_device_set_name(device, eir_data.name);
		void btd_device_device_set_name(struct btd_device *device, const char *name)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			if (strncmp(name, device->name, MAX_NAME_LENGTH) == 0) //GM in here
				return;

			DBG("%s %s", device->path, name);

			strncpy(device->name, name, MAX_NAME_LENGTH);

			store_device_info(device);

			g_dbus_emit_property_changed(dbus_conn, device->path,
								DEVICE_INTERFACE, "Name");

			if (device->alias != NULL)
				return;

			g_dbus_emit_property_changed(dbus_conn, device->path,
								DEVICE_INTERFACE, "Alias");
		}
	}

	if (eir_data.msd_list) {
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
		adapter_msd_notify(adapter, device, eir_data.msd_list);
	}

	eir_data_free(&eir_data);
	printf("jokerb %s:in %d.\n",__func__,__LINE__); //
}
// GM: 执行完connected_callback(), 就执行这个函数了..
static void new_link_key_callback(uint16_t index, uint16_t length,
					const void *param, void *user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	const struct mgmt_ev_new_link_key *ev = param;
	const struct mgmt_addr_info *addr = &ev->key.addr;
	struct btd_adapter *adapter = user_data;
	struct btd_device *device;
	char dst[18];

	if (length < sizeof(*ev)) {
		btd_error(adapter->dev_id, "Too small new link key event");
		return;
	}

	ba2str(&addr->bdaddr, dst);

	DBG("hci%u new key for %s type %u pin_len %u store_hint %u",
		adapter->dev_id, dst, ev->key.type, ev->key.pin_len,
		ev->store_hint);
	//hci0 new key for 04:57:91:CC:BB:0E type 4 pin_len 0 store_hint 1

	if (ev->key.pin_len > 16) {
		btd_error(adapter->dev_id,
				"Invalid PIN length (%u) in new_key event",
							ev->key.pin_len);
		return;
	}

	device = btd_adapter_get_device(adapter, &addr->bdaddr, addr->type);
	if (!device) {
		btd_error(adapter->dev_id,
				"Unable to get device object for %s", dst);
		return;
	}
	struct btd_device *btd_adapter_get_device(struct btd_adapter *adapter,
						const bdaddr_t *addr,
						uint8_t addr_type)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct btd_device *device;

		if (!adapter) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			return NULL;
		}

		device = btd_adapter_find_device(adapter, addr, addr_type);
		if (device) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			return device;
		}
		struct btd_device *btd_adapter_find_device(struct btd_adapter *adapter,
									const bdaddr_t *dst,
									uint8_t bdaddr_type)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			struct device_addr_type addr;
			struct btd_device *device;
			GSList *list;

			if (!adapter) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
				return NULL;
			}

			bacpy(&addr.bdaddr, dst);
			addr.bdaddr_type = bdaddr_type;

			list = g_slist_find_custom(adapter->devices, &addr,
									device_addr_type_cmp);
			if (!list) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
				return NULL;
			}

			device = list->data;

			/*
			 * If we're looking up based on public address and the address
			 * was not previously used over this bearer we may need to
			 * update LE or BR/EDR support information.
			 */
			if (bdaddr_type == BDADDR_BREDR) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__); //
				device_set_bredr_support(device);
				void device_set_bredr_support(struct btd_device *device)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					if (device->bredr) { // GM in here
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
						return;
					}

					device->bredr = true;
					store_device_info(device);
				}
			}
			else {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
				device_set_le_support(device, bdaddr_type);
			}

			printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			return device;
		}

		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		return adapter_create_device(adapter, addr, addr_type);
	}

	if (ev->store_hint) { //GM in here
		const struct mgmt_link_key_info *key = &ev->key;

		/* GM: 往/userdat/lib/bluetoothd/xxx/设备地址/info 文件内写入link_key信息 */
		store_link_key(adapter, device, key->val, key->type, key->pin_len);
		static void store_link_key(struct btd_adapter *adapter,
						struct btd_device *device, const uint8_t *key,
						uint8_t type, uint8_t pin_length)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			char device_addr[18];
			char filename[PATH_MAX];
			GKeyFile *key_file;
			gsize length = 0;
			char key_str[33];
			char *str;
			int i;

			ba2str(device_get_address(device), device_addr);

			snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info",
							adapter_dir(adapter), device_addr);
			key_file = g_key_file_new();
			g_key_file_load_from_file(key_file, filename, 0, NULL);

			for (i = 0; i < 16; i++)
				sprintf(key_str + (i * 2), "%2.2X", key[i]);

			g_key_file_set_string(key_file, "LinkKey", "Key", key_str);

			g_key_file_set_integer(key_file, "LinkKey", "Type", type);
			g_key_file_set_integer(key_file, "LinkKey", "PINLength", pin_length);

			create_file(filename, S_IRUSR | S_IWUSR);

			str = g_key_file_to_data(key_file, &length, NULL);
			g_file_set_contents(filename, str, length, NULL);
			g_free(str);

			g_key_file_free(key_file);
		}

		device_set_bonded(device, BDADDR_BREDR);
		void device_set_bonded(struct btd_device *device, uint8_t bdaddr_type)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			if (!device)
				return;

			DBG("");

			if (bdaddr_type == BDADDR_BREDR) // GM in here
				device->bredr_state.bonded = true; <tag67>
			else
				device->le_state.bonded = true;

			btd_device_set_temporary(device, false);
			void btd_device_set_temporary(struct btd_device *device, bool temporary)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				DBG("");
				if (!device) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
					return;
				}

				if (device->temporary == temporary) { //GM in this context, will goto here
				printf("jokerb %s:in %d.\n",__func__,__LINE__); //
					return;
				}

				if (device_address_is_private(device)) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
					return;
				}

				DBG("temporary %d", temporary);

				device->temporary = temporary;

				if (temporary) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
					if (device->bredr) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
						adapter_whitelist_remove(device->adapter, device);
					}
					adapter_connect_list_remove(device->adapter, device);
					return;
				}

				if (device->bredr) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__); //
					adapter_whitelist_add(device->adapter, device);
				}

				store_device_info(device);
				printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			}
		}
	}

	bonding_complete(adapter, &addr->bdaddr, addr->type, 0);
	static void bonding_complete(struct btd_adapter *adapter,
						const bdaddr_t *bdaddr,
						uint8_t addr_type, uint8_t status)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct btd_device *device;

		if (status == 0) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			device = btd_adapter_get_device(adapter, bdaddr, addr_type);
		}
		else {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			device = btd_adapter_find_device(adapter, bdaddr, addr_type);
		}

		if (device != NULL) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			device_bonding_complete(device, addr_type, status);
			void device_bonding_complete(struct btd_device *device, uint8_t bdaddr_type,
											uint8_t status)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct bonding_req *bonding = device->bonding;
				struct authentication_req *auth = device->authr;
				struct bearer_state *state = get_state(device, bdaddr_type);

				DBG("bonding %p status 0x%02x", bonding, status);

				if (auth && auth->agent) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
					agent_cancel(auth->agent);
				}

				if (status) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
					device_cancel_authentication(device, TRUE);
					device_bonding_failed(device, status);
					return;
				}

				device_auth_req_free(device);
				static void device_auth_req_free(struct btd_device *device)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct authentication_req *authr = device->authr;

					if (!authr)
						return;

					if (authr->agent)
						agent_unref(authr->agent);

					g_free(authr->pincode);
					g_free(authr);

					device->authr = NULL;
				}

				/* If we're already paired nothing more is needed */
				if (state->paired) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
					return;
				}

				device_set_paired(device, bdaddr_type);
				void device_set_paired(struct btd_device *dev, uint8_t bdaddr_type)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct bearer_state *state = get_state(dev, bdaddr_type);

					if (state->paired)
						return;

					state->paired = true; <tag69>

					/* If the other bearer state was alraedy true we don't need to
					 * send any property signals.
					 */
					if (dev->bredr_state.paired == dev->le_state.paired)
						return;

					if (!state->svc_resolved) {
						dev->pending_paired = true;
						return;
					}

					g_dbus_emit_property_changed(dbus_conn, dev->path,
										DEVICE_INTERFACE, "Paired");
				}

				/* If services are already resolved just reply to the pairing
				 * request
				 */
				if (state->svc_resolved && bonding) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
					/* Attept to store services for this device failed because it
					 * was not paired. Now that we're paired retry. */
					store_gatt_db(device);

					g_dbus_send_reply(dbus_conn, bonding->msg, DBUS_TYPE_INVALID);
					bonding_request_free(bonding);
					return;
				}

				/* If we were initiators start service discovery immediately.
				 * However if the other end was the initator wait a few seconds
				 * before SDP. This is due to potential IOP issues if the other
				 * end starts doing SDP at the same time as us */
				if (bonding) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__); //
					DBG("Proceeding with service discovery");
					/* If we are initiators remove any discovery timer and just
					 * start discovering services directly */
					if (device->discov_timer) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
						g_source_remove(device->discov_timer);
						device->discov_timer = 0;
					}

					if (bdaddr_type == BDADDR_BREDR) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__); //
						device_browse_sdp(device, bonding->msg);
						static int device_browse_sdp(struct btd_device *device, DBusMessage *msg)
						{
							printf("jokerb %s:in %d.\n",__func__,__LINE__);
							struct btd_adapter *adapter = device->adapter;
							struct browse_req *req;
							uuid_t uuid;
							int err;

							DBG("");
							req = browse_request_new(device, BROWSE_SDP, msg);
							if (!req)
								return -EBUSY;
							static struct browse_req *browse_request_new(struct btd_device *device,
														uint8_t type,
														DBusMessage *msg)
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								struct browse_req *req;

								if (device->browse)
									return NULL;

								req = g_new0(struct browse_req, 1);
								req->device = device;
								req->type = type;

								device->browse = req;

								if (!msg)
									return req;

								req->msg = dbus_message_ref(msg);

								/*
								 * Track the request owner to cancel it automatically if the owner
								 * exits
								 */
								req->listener_id = g_dbus_add_disconnect_watch(dbus_conn,
													dbus_message_get_sender(msg),
													browse_request_exit,
													req, NULL);

								return req;
							}

							sdp_uuid16_create(&uuid, uuid_list[req->search_uuid++]);
							uuid_t *sdp_uuid16_create(uuid_t *u, uint16_t val)
							{
								memset(u, 0, sizeof(uuid_t));
								u->type = SDP_UUID16;
								u->value.uuid16 = val;
								return u;
							}

							req->sdp_flags = get_sdp_flags(device);
							static uint16_t get_sdp_flags(struct btd_device *device)
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								uint16_t vid, pid;

								vid = btd_device_get_vendor(device);
								pid = btd_device_get_product(device);

								/* Sony DualShock 4 is not respecting negotiated L2CAP MTU. This might
								 * results in SDP response being dropped by kernel. Workaround this by
								 * forcing SDP code to use bigger MTU while connecting.
								 */
								if (vid == 0x054c && pid == 0x05c4)
									return SDP_LARGE_MTU;

								if (btd_adapter_ssp_enabled(device->adapter))
									return 0;

								/* if no EIR try matching Sony DualShock 4 with name and class */
								if (!strncmp(device->name, "Wireless Controller", MAX_NAME_LENGTH) &&
										device->class == 0x2508)
									return SDP_LARGE_MTU;

								return 0;
							}

							err = bt_search_service(btd_adapter_get_address(adapter),
										&device->bdaddr, &uuid, browse_cb, req, NULL,
										req->sdp_flags);
							
							if (err < 0) {
								browse_request_free(req);
								return err;
							}
							int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst,
										uuid_t *uuid, bt_callback_t cb, void *user_data,
										bt_destroy_t destroy, uint16_t flags)
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								struct search_context *ctxt = NULL;
								int err;

								if (!cb)
									return -EINVAL;

								err = create_search_context(&ctxt, src, dst, uuid, flags);
								if (err < 0)
									return err;
								static int create_search_context(struct search_context **ctxt,
													const bdaddr_t *src,
													const bdaddr_t *dst,
													uuid_t *uuid, uint16_t flags)
								{
									printf("jokerb %s:in %d.\n",__func__,__LINE__);
									sdp_session_t *s;
									GIOChannel *chan;
									uint32_t prio = 1;
									int sk;

									if (!ctxt)
										return -EINVAL;

									s = get_cached_sdp_session(src, dst);
									if (!s)
										s = sdp_connect(src, dst, SDP_NON_BLOCKING | flags); //
									static sdp_session_t *get_cached_sdp_session(const bdaddr_t *src,
																const bdaddr_t *dst)
									{
										printf("jokerb %s:in %d.\n",__func__,__LINE__);
										GSList *l;

										for (l = cached_sdp_sessions; l != NULL; l = l->next) {
											struct cached_sdp_session *c = l->data;
											sdp_session_t *session;

											if (bacmp(&c->src, src) || bacmp(&c->dst, dst))
												continue;

											//g_source_remove(c->timer);
											g_source_remove(c->io_id);

											session = c->session;

											cached_sdp_sessions = g_slist_remove(cached_sdp_sessions, c);
											g_free(c);

											return session;
										}

										return NULL;
									}
									sdp_session_t *sdp_connect(const bdaddr_t *src,
											const bdaddr_t *dst, uint32_t flags)
									{
										printf("jokerb %s:in %d.\n",__func__,__LINE__);
										sdp_session_t *session;
										int err;

										if ((flags & SDP_RETRY_IF_BUSY) && (flags & SDP_NON_BLOCKING)) {
											errno = EINVAL;
											return NULL;
										}

										session = sdp_create(-1, flags);
										if (!session)
											return NULL;

										if (sdp_is_local(dst)) {
											if (sdp_connect_local(session) < 0)
												goto fail;
										} else {
											SDPDBG("sdp connect to l2cap\n"); //
											if (sdp_connect_l2cap(src, dst, session) < 0)
												goto fail;
										}
										static int sdp_connect_l2cap(const bdaddr_t *src,
												const bdaddr_t *dst, sdp_session_t *session)
										{
											printf("jokerb %s:in %d.\n",__func__,__LINE__);
											uint32_t flags = session->flags;
											struct sockaddr_l2 sa;
											int sk;
											int sockflags = SOCK_SEQPACKET | SOCK_CLOEXEC;

											if (flags & SDP_NON_BLOCKING)
												sockflags |= SOCK_NONBLOCK;

											session->sock = socket(PF_BLUETOOTH, sockflags, BTPROTO_L2CAP);
											if (session->sock < 0)
												return -1;
											session->local = 0;

											sk = session->sock;

											memset(&sa, 0, sizeof(sa));

											sa.l2_family = AF_BLUETOOTH;
											sa.l2_psm = 0;

											if (bacmp(src, BDADDR_ANY)) {
												sa.l2_bdaddr = *src;
												if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0)
													return -1;
											}

											if (flags & SDP_WAIT_ON_CLOSE) {
												struct linger l = { .l_onoff = 1, .l_linger = 1 };
												setsockopt(sk, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
											}

											if ((flags & SDP_LARGE_MTU) &&
														set_l2cap_mtu(sk, SDP_LARGE_L2CAP_MTU) < 0)
												return -1;

											sa.l2_psm = htobs(SDP_PSM);
											sa.l2_bdaddr = *dst;

											do {
												int ret = connect(sk, (struct sockaddr *) &sa, sizeof(sa));
												if (!ret)
													return 0;
												if (ret < 0 && (flags & SDP_NON_BLOCKING) &&
														(errno == EAGAIN || errno == EINPROGRESS))
													return 0;
											} while (errno == EBUSY && (flags & SDP_RETRY_IF_BUSY));

											return -1;
										}

										return session;

									fail:
										err = errno;
										if (session->sock >= 0) {
											SDPDBG("close session->sock\n");
											close(session->sock);
										}
										free(session->priv);
										free(session);
										errno = err;

										return NULL;
									}

									if (!s)
										return -errno;

									*ctxt = g_try_malloc0(sizeof(struct search_context));
									if (!*ctxt) {
										DBG("close session->sock\n");
										sdp_close(s);
										return -ENOMEM;
									}

									bacpy(&(*ctxt)->src, src);
									bacpy(&(*ctxt)->dst, dst);
									(*ctxt)->session = s;
									(*ctxt)->uuid = *uuid;

									sk = sdp_get_socket(s);
									/* Set low priority for the SDP connection not to interfere with
									 * other potential traffic.
									 */
									if (setsockopt(sk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)) < 0)
										warn("Setting SDP priority failed: %s (%d)",
														strerror(errno), errno);

									chan = g_io_channel_unix_new(sk);
									(*ctxt)->io_id = g_io_add_watch(chan,
												G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
												connect_watch, *ctxt);
									g_io_channel_unref(chan);

									DBG("unref chan and return\n");
									return 0;
								}

								ctxt->cb	= cb;
								ctxt->destroy	= destroy;
								ctxt->user_data	= user_data;

								context_list = g_slist_append(context_list, ctxt);

								return 0;
							}

							return err;
						}
					}
					else {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
						DBG("");
						device_browse_gatt(device, bonding->msg);
					}

					bonding_request_free(bonding);
				} else if (!state->svc_resolved) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
					if (!device->browse && !device->discov_timer &&
							main_opts.reverse_sdp) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
						/* If we are not initiators and there is no currently
						 * active discovery or discovery timer, set discovery
						 * timer */
						DBG("setting timer for reverse service discovery");
						device->discov_timer = g_timeout_add_seconds(
										DISCOVERY_TIMER,
										start_discovery,
										device);
					}
				}
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
			}
		}

		resume_discovery(adapter);

		check_oob_bonding_complete(adapter, bdaddr, status);
		static void check_oob_bonding_complete(struct btd_adapter *adapter,
							const bdaddr_t *bdaddr, uint8_t status)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			if (!adapter->oob_handler || !adapter->oob_handler->bonding_cb) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__); //
				return;
			}

			if (bacmp(bdaddr, &adapter->oob_handler->remote_addr) != 0) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
				return;
			}

			adapter->oob_handler->bonding_cb(adapter, bdaddr, status,
							adapter->oob_handler->user_data);

			g_free(adapter->oob_handler);
			adapter->oob_handler = NULL;
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
		}
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
	}
}
// GM: 执行完new_link_key_callback(), 执行这个.
static void pair_device_complete(uint8_t status, uint16_t length,
					const void *param, void *user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	const struct mgmt_rp_pair_device *rp = param;
	struct pair_device_data *data = user_data;
	struct btd_adapter *adapter = data->adapter;

	DBG("%s (0x%02x)", mgmt_errstr(status), status);
	//Authentication Failed (0x05)
	//Success (0x00)

	adapter->pair_device_id = 0;

	if (adapter->pair_device_timeout > 0) { //GM in here
		g_source_remove(adapter->pair_device_timeout);
		adapter->pair_device_timeout = 0;
	}

	/* Workaround for a kernel bug
	 *
	 * Broken kernels may reply to device pairing command with command
	 * status instead of command complete event e.g. if adapter was not
	 * powered.
	 */
	if (status != MGMT_STATUS_SUCCESS && length < sizeof(*rp)) {
		btd_error(adapter->dev_id, "Pair device failed: %s (0x%02x)",
						mgmt_errstr(status), status);

		bonding_attempt_complete(adapter, &data->bdaddr,data->addr_type, status);
		return;
	}

	if (length < sizeof(*rp)) {
		btd_error(adapter->dev_id, "Too small pair device response");
		return;
	}

	bonding_attempt_complete(adapter, &rp->addr.bdaddr, rp->addr.type,status);
	static void bonding_attempt_complete(struct btd_adapter *adapter,
						const bdaddr_t *bdaddr,
						uint8_t addr_type, uint8_t status)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct btd_device *device;
		char addr[18];

		ba2str(bdaddr, addr);
		DBG("hci%u bdaddr %s type %u status 0x%x", adapter->dev_id, addr, addr_type, status);
		//hci0 bdaddr 04:57:91:CC:BB:0E type 0 status 0x0

		if (status == 0) //gm: here
			device = btd_adapter_get_device(adapter, bdaddr, addr_type);
		else
			device = btd_adapter_find_device(adapter, bdaddr, addr_type);
		struct btd_device *btd_adapter_get_device(struct btd_adapter *adapter,
							const bdaddr_t *addr,
							uint8_t addr_type)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			struct btd_device *device;

			if (!adapter)
				return NULL;

			device = btd_adapter_find_device(adapter, addr, addr_type);
			if (device) //GM: return here.
				return device;
			struct btd_device *btd_adapter_find_device(struct btd_adapter *adapter,
										const bdaddr_t *dst,
										uint8_t bdaddr_type)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct device_addr_type addr;
				struct btd_device *device;
				GSList *list;

				if (!adapter)
					return NULL;

				bacpy(&addr.bdaddr, dst);
				addr.bdaddr_type = bdaddr_type;

				list = g_slist_find_custom(adapter->devices, &addr,
										device_addr_type_cmp);
				if (!list)
					return NULL;

				device = list->data;

				/*
				 * If we're looking up based on public address and the address
				 * was not previously used over this bearer we may need to
				 * update LE or BR/EDR support information.
				 */
				if (bdaddr_type == BDADDR_BREDR) {
					device_set_bredr_support(device);
					void device_set_bredr_support(struct btd_device *device)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						if (device->bredr)
							return;

						device->bredr = true;
						store_device_info(device);
						static void store_device_info(struct btd_device *device)
						{
							printf("jokerb %s:in %d.\n",__func__,__LINE__);
							if (device->temporary || device->store_id > 0)
								return;

							if (device_address_is_private(device)) {
								warn("Can't store info for private addressed device %s",
														device->path);
								return;
							}

							device->store_id = g_idle_add(store_device_info_cb, device);
						}
					}
				}
				else
					device_set_le_support(device, bdaddr_type);

				return device;
			}

			return adapter_create_device(adapter, addr, addr_type); //GM: return before. no exec
		}

		if (status == MGMT_STATUS_AUTH_FAILED && adapter->pincode_requested) {
			/* On faliure, issue a bonding_retry if possible. */
			if (device != NULL) {
				if (device_bonding_attempt_retry(device) == 0)
					return;
			}
		}

		/* Ignore disconnects during retry. */
		if (status == MGMT_STATUS_DISCONNECTED &&
						device && device_is_retrying(device))
			return;

		/* In any other case, finish the bonding. */
		bonding_complete(adapter, bdaddr, addr_type, status);
		static void bonding_complete(struct btd_adapter *adapter,
							const bdaddr_t *bdaddr,
							uint8_t addr_type, uint8_t status)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			struct btd_device *device;

			if (status == 0) {
				device = btd_adapter_get_device(adapter, bdaddr, addr_type);
			}
			else
				device = btd_adapter_find_device(adapter, bdaddr, addr_type);

			if (device != NULL) {
				device_bonding_complete(device, addr_type, status);
				void device_bonding_complete(struct btd_device *device, uint8_t bdaddr_type,
												uint8_t status)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct bonding_req *bonding = device->bonding;
					struct authentication_req *auth = device->authr;
					struct bearer_state *state = get_state(device, bdaddr_type);

					DBG("bonding %p status 0x%02x", bonding, status);

					if (auth && auth->agent) {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
						agent_cancel(auth->agent);
					}

					if (status) {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
						device_cancel_authentication(device, TRUE);
						device_bonding_failed(device, status);
						return;
					}

					device_auth_req_free(device);

					/* If we're already paired nothing more is needed */
					if (state->paired) { // GM in here
					printf("jokerb %s:in %d.\n",__func__,__LINE__); //
						return;
					}

					device_set_paired(device, bdaddr_type);

					/* If services are already resolved just reply to the pairing
					 * request
					 */
					if (state->svc_resolved && bonding) {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
						/* Attept to store services for this device failed because it
						 * was not paired. Now that we're paired retry. */
						store_gatt_db(device);

						g_dbus_send_reply(dbus_conn, bonding->msg, DBUS_TYPE_INVALID);
						bonding_request_free(bonding);
						return;
					}

					/* If we were initiators start service discovery immediately.
					 * However if the other end was the initator wait a few seconds
					 * before SDP. This is due to potential IOP issues if the other
					 * end starts doing SDP at the same time as us */
					if (bonding) {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
						DBG("Proceeding with service discovery");
						/* If we are initiators remove any discovery timer and just
						 * start discovering services directly */
						if (device->discov_timer) {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
							g_source_remove(device->discov_timer);
							device->discov_timer = 0;
						}

						if (bdaddr_type == BDADDR_BREDR) {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
							device_browse_sdp(device, bonding->msg);
						}
						else {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
							DBG("");
							device_browse_gatt(device, bonding->msg);
						}

						bonding_request_free(bonding);
					} else if (!state->svc_resolved) {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
						if (!device->browse && !device->discov_timer &&
								main_opts.reverse_sdp) {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
							/* If we are not initiators and there is no currently
							 * active discovery or discovery timer, set discovery
							 * timer */
							DBG("setting timer for reverse service discovery");
							device->discov_timer = g_timeout_add_seconds(
											DISCOVERY_TIMER,
											start_discovery,
											device);
						}
					}
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
				}
			}

			resume_discovery(adapter);
			static void resume_discovery(struct btd_adapter *adapter)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				DBG("");

				adapter->discovery_suspended = false;

				/*
				 * If there are no clients discovering right now, then there is
				 * also nothing to resume.
				 */
				if (!adapter->discovery_list)
					return;

				/*
				 * Treat a suspended discovery session the same as extra long
				 * idle time for a normal discovery. So just trigger the default
				 * restart procedure.
				 */
				trigger_start_discovery(adapter, IDLE_DISCOV_TIMEOUT);
				static void trigger_start_discovery(struct btd_adapter *adapter, guint delay)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);

					DBG("");

					cancel_passive_scanning(adapter);

					if (adapter->discovery_idle_timeout > 0) {
						g_source_remove(adapter->discovery_idle_timeout);
						adapter->discovery_idle_timeout = 0;
					}

					/*
					 * If the controller got powered down in between, then ensure
					 * that we do not keep trying to restart discovery.
					 *
					 * This is safe-guard and should actually never trigger.
					 */
					if (!(adapter->current_settings & MGMT_SETTING_POWERED))
						return;

					adapter->discovery_idle_timeout = g_timeout_add_seconds(delay,
									start_discovery_timeout, adapter);
				}
			}

			check_oob_bonding_complete(adapter, bdaddr, status);
			static void check_oob_bonding_complete(struct btd_adapter *adapter,
								const bdaddr_t *bdaddr, uint8_t status)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				if (!adapter->oob_handler || !adapter->oob_handler->bonding_cb)
					return;

				if (bacmp(bdaddr, &adapter->oob_handler->remote_addr) != 0)
					return;

				adapter->oob_handler->bonding_cb(adapter, bdaddr, status,
								adapter->oob_handler->user_data);

				g_free(adapter->oob_handler);
				adapter->oob_handler = NULL;
			}
		}
	}
}
//sdp 搜索到了profile, 产生事件, 引起该callback.
connect_watch
static gboolean connect_watch(GIOChannel *chan, GIOCondition cond,
							gpointer user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct search_context *ctxt = user_data;
	sdp_list_t *search, *attrids;
	uint32_t range = 0x0000ffff;
	socklen_t len;
	int sk, err, sk_err = 0;

	sk = g_io_channel_unix_get_fd(chan);
	ctxt->io_id = 0;

	len = sizeof(sk_err);
	if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
		err = -errno;
	else
		err = -sk_err;

	if (err != 0)
		goto failed;

	if (sdp_set_notify(ctxt->session, search_completed_cb, ctxt) < 0) {
		err = -EIO;
		goto failed;
	}
	int sdp_set_notify(sdp_session_t *session, sdp_callback_t *func, void *udata)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct sdp_transaction *t;

		if (!session || !session->priv)
			return -1;

		t = session->priv;
		t->cb = func;
		t->udata = udata;

		return 0;
	}

	search = sdp_list_append(NULL, &ctxt->uuid);
	sdp_list_t *sdp_list_append(sdp_list_t *p, void *d)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		sdp_list_t *q, *n = malloc(sizeof(sdp_list_t));

		if (!n)
			return NULL;

		n->data = d;
		n->next = 0;

		if (!p)
			return n;

		for (q = p; q->next; q = q->next);
		q->next = n;

		return p;
	}
	attrids = sdp_list_append(NULL, &range);
	if (sdp_service_search_attr_async(ctxt->session,
				search, SDP_ATTR_REQ_RANGE, attrids) < 0) {
		sdp_list_free(attrids, NULL);
		sdp_list_free(search, NULL);
		err = -EIO;
		goto failed;
	}
	int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *search,
								sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct sdp_transaction *t;
		sdp_pdu_hdr_t *reqhdr;
		uint8_t *pdata;
		int cstate_len, seqlen = 0;

		if (!session || !session->priv)
			return -1;

		t = session->priv;

		/* clean possible allocated buffer */
		free(t->rsp_concat_buf.data);
		memset(&t->rsp_concat_buf, 0, sizeof(sdp_buf_t));

		if (!t->reqbuf) {
			t->reqbuf = malloc(SDP_REQ_BUFFER_SIZE);
			if (!t->reqbuf) {
				t->err = ENOMEM;
				goto end;
			}
		}
		memset(t->reqbuf, 0, SDP_REQ_BUFFER_SIZE);

		reqhdr = (sdp_pdu_hdr_t *) t->reqbuf;
		reqhdr->tid = htons(sdp_gen_tid(session));
		reqhdr->pdu_id = SDP_SVC_SEARCH_ATTR_REQ;

		/* generate PDU */
		pdata = t->reqbuf + sizeof(sdp_pdu_hdr_t);
		t->reqsize = sizeof(sdp_pdu_hdr_t);

		/* add service class IDs for search */
		seqlen = gen_searchseq_pdu(pdata, search); //
		static int gen_searchseq_pdu(uint8_t *dst, const sdp_list_t *seq)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			uuid_t *uuid = seq->data;
			return gen_dataseq_pdu(dst, seq, uuid->type);
			static int gen_dataseq_pdu(uint8_t *dst, const sdp_list_t *seq, uint8_t dtd)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				sdp_data_t *dataseq;
				void **types, **values;
				sdp_buf_t buf;
				int i, seqlen = sdp_list_len(seq);

				/* Fill up the value and the dtd arrays */
				SDPDBG("");

				SDPDBG("Seq length : %d", seqlen);

				types = malloc(seqlen * sizeof(void *));
				if (!types)
					return -ENOMEM;

				values = malloc(seqlen * sizeof(void *));
				if (!values) {
					free(types);
					return -ENOMEM;
				}

				for (i = 0; i < seqlen; i++) {
					void *data = seq->data;
					types[i] = &dtd;
					if (SDP_IS_UUID(dtd))
						data = &((uuid_t *)data)->value;
					values[i] = data;
					seq = seq->next;
				}

				dataseq = sdp_seq_alloc(types, values, seqlen);
				if (!dataseq) {
					free(types);
					free(values);
					return -ENOMEM;
				}

				memset(&buf, 0, sizeof(sdp_buf_t));
				sdp_gen_buffer(&buf, dataseq);
				buf.data = malloc(buf.buf_size);

				if (!buf.data) {
					sdp_data_free(dataseq);
					free(types);
					free(values);
					return -ENOMEM;
				}

				SDPDBG("Data Seq : 0x%p", seq);
				seqlen = sdp_gen_pdu(&buf, dataseq);
				int sdp_gen_pdu(sdp_buf_t *buf, sdp_data_t *d)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					uint32_t pdu_size, data_size;
					unsigned char *src = NULL, is_seq = 0, is_alt = 0;
					uint16_t u16;
					uint32_t u32;
					uint64_t u64;
					uint128_t u128;
					uint8_t *seqp = buf->data + buf->data_size;
					uint32_t orig_data_size = buf->data_size;

				recalculate:
					pdu_size = sdp_get_data_type_size(d->dtd);
					buf->data_size += pdu_size;

					data_size = sdp_get_data_size(buf, d);
					if (data_size > UCHAR_MAX && d->dtd == SDP_SEQ8) {
						buf->data_size = orig_data_size;
						d->dtd = SDP_SEQ16;
						goto recalculate;
					}

					*seqp = d->dtd;

					switch (d->dtd) {
					case SDP_DATA_NIL:
						break;
					case SDP_UINT8:
						src = &d->val.uint8;
						break;
					case SDP_UINT16:
						u16 = htons(d->val.uint16);
						src = (unsigned char *) &u16;
						break;
					case SDP_UINT32:
						u32 = htonl(d->val.uint32);
						src = (unsigned char *) &u32;
						break;
					case SDP_UINT64:
						u64 = hton64(d->val.uint64);
						src = (unsigned char *) &u64;
						break;
					case SDP_UINT128:
						hton128(&d->val.uint128, &u128);
						src = (unsigned char *) &u128;
						break;
					case SDP_INT8:
					case SDP_BOOL:
						src = (unsigned char *) &d->val.int8;
						break;
					case SDP_INT16:
						u16 = htons(d->val.int16);
						src = (unsigned char *) &u16;
						break;
					case SDP_INT32:
						u32 = htonl(d->val.int32);
						src = (unsigned char *) &u32;
						break;
					case SDP_INT64:
						u64 = hton64(d->val.int64);
						src = (unsigned char *) &u64;
						break;
					case SDP_INT128:
						hton128(&d->val.int128, &u128);
						src = (unsigned char *) &u128;
						break;
					case SDP_TEXT_STR8:
					case SDP_TEXT_STR16:
					case SDP_TEXT_STR32:
					case SDP_URL_STR8:
					case SDP_URL_STR16:
					case SDP_URL_STR32:
						src = (unsigned char *) d->val.str;
						sdp_set_seq_len(seqp, data_size);
						break;
					case SDP_SEQ8:
					case SDP_SEQ16:
					case SDP_SEQ32:
						is_seq = 1;
						sdp_set_seq_len(seqp, data_size);
						break;
					case SDP_ALT8:
					case SDP_ALT16:
					case SDP_ALT32:
						is_alt = 1;
						sdp_set_seq_len(seqp, data_size);
						break;
					case SDP_UUID16:
						u16 = htons(d->val.uuid.value.uuid16);
						src = (unsigned char *) &u16;
						break;
					case SDP_UUID32:
						u32 = htonl(d->val.uuid.value.uuid32);
						src = (unsigned char *) &u32;
						break;
					case SDP_UUID128:
						src = (unsigned char *) &d->val.uuid.value.uuid128;
						break;
					default:
						break;
					}

					if (!is_seq && !is_alt) {
						if (src && buf->buf_size >= buf->data_size + data_size) {
							memcpy(buf->data + buf->data_size, src, data_size);
							buf->data_size += data_size;
						} else if (d->dtd != SDP_DATA_NIL) {
							SDPDBG("Gen PDU : Can't copy from invalid source or dest");
						}
					}

					pdu_size += data_size;

					return pdu_size;
				}
				SDPDBG("Copying : %d", buf.data_size);
				memcpy(dst, buf.data, buf.data_size);

				sdp_data_free(dataseq);

				free(types);
				free(values);
				free(buf.data);
				return seqlen;
			}
		}

		SDPDBG("Data seq added : %d", seqlen);
		//Data seq added : 5

		/* now set the length and increment the pointer */
		t->reqsize += seqlen;
		pdata += seqlen;

		bt_put_be16(SDP_MAX_ATTR_LEN, pdata);
		t->reqsize += sizeof(uint16_t);
		pdata += sizeof(uint16_t);

		SDPDBG("Max attr byte count : %d", SDP_MAX_ATTR_LEN);
		//Max attr byte count : 65535

		/* get attr seq PDU form */
		seqlen = gen_attridseq_pdu(pdata, attrid_list,reqtype == SDP_ATTR_REQ_INDIVIDUAL ? SDP_UINT16 : SDP_UINT32);
		if (seqlen == -1) {
			t->err = EINVAL;
			goto end;
		}
		static int gen_attridseq_pdu(uint8_t *dst, const sdp_list_t *seq, uint8_t dataType)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			return gen_dataseq_pdu(dst, seq, dataType);
		}

		pdata += seqlen;
		SDPDBG("Attr list length : %d", seqlen);
		//Attr list length : 7
		t->reqsize += seqlen;

		/* set the request header's param length */
		cstate_len = copy_cstate(pdata, SDP_REQ_BUFFER_SIZE - t->reqsize, NULL);
		static int copy_cstate(uint8_t *pdata, int pdata_len, const sdp_cstate_t *cstate)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			if (cstate) {
				uint8_t len = cstate->length;
				if (len >= pdata_len) {
					SDPERR("Continuation state size exceeds internal buffer");
					len = pdata_len - 1;
				}
				*pdata++ = len;
				memcpy(pdata, cstate->data, len);
				return len + 1;
			}
			*pdata = 0;
			return 1;
		}
		reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t));

		if (sdp_send_req(session, t->reqbuf, t->reqsize + cstate_len) < 0) {
			SDPERR("Error sending data:%m");
			t->err = errno;
			goto end;
		}
		static int sdp_send_req(sdp_session_t *session, uint8_t *buf, uint32_t size)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			uint32_t sent = 0;

			while (sent < size) {
				int n = send(session->sock, buf + sent, size - sent, 0);
				if (n < 0)
					return -1;
				sent += n;
			}
			return 0;
		}

		return 0;
	end:

		free(t->reqbuf);
		t->reqbuf = NULL;

		return -1;
	}

	sdp_list_free(attrids, NULL);
	sdp_list_free(search, NULL);

	/* Set callback responsible for update the internal SDP transaction */
	ctxt->io_id = g_io_add_watch(chan,
				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
				search_process_cb, ctxt); //
	return FALSE;

failed:
    DBG("close session->sock\n");
	sdp_close(ctxt->session);
	ctxt->session = NULL;

	if (ctxt->cb)
		ctxt->cb(NULL, err, ctxt->user_data);

	search_context_cleanup(ctxt);

	return FALSE;
}
//connect_watch()执行完, 就到这里了
search_process_cb
static gboolean search_process_cb(GIOChannel *chan, GIOCondition cond,
							gpointer user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct search_context *ctxt = user_data;

	if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
        DBG("close session->sock\n");
		sdp_close(ctxt->session);
		ctxt->session = NULL;

		if (ctxt->cb)
			ctxt->cb(NULL, -EIO, ctxt->user_data);

		search_context_cleanup(ctxt);
		return FALSE;
	}

	/* If sdp_process fails it calls search_completed_cb */
	if (sdp_process(ctxt->session) < 0)
		return FALSE;
	int sdp_process(sdp_session_t *session)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct sdp_transaction *t;
		sdp_pdu_hdr_t *reqhdr, *rsphdr;
		sdp_cstate_t *pcstate;
		uint8_t *pdata, *rspbuf, *targetPtr;
		int rsp_count, err = -1;
		size_t size = 0;
		int n, plen;
		uint16_t status = 0xffff;
		uint8_t pdu_id = 0x00;

		if (!session || !session->priv) {
			SDPERR("Invalid session");
			return -1;
		}

		rspbuf = malloc(SDP_RSP_BUFFER_SIZE);
		if (!rspbuf) {
			SDPERR("Response buffer alloc failure:%m (%d)", errno);
			return -1;
		}

		memset(rspbuf, 0, SDP_RSP_BUFFER_SIZE);

		t = session->priv;
		reqhdr = (sdp_pdu_hdr_t *)t->reqbuf;
		rsphdr = (sdp_pdu_hdr_t *)rspbuf;

		pdata = rspbuf + sizeof(sdp_pdu_hdr_t);

		n = sdp_read_rsp(session, rspbuf, SDP_RSP_BUFFER_SIZE);
		if (n < 0) {
			SDPERR("Read response:%m (%d)", errno);
			t->err = errno;
			goto end;
		}
		static int sdp_read_rsp(sdp_session_t *session, uint8_t *buf, uint32_t size)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			fd_set readFds;
			struct timeval timeout = { SDP_RESPONSE_TIMEOUT, 0 };

			FD_ZERO(&readFds);
			FD_SET(session->sock, &readFds);
			SDPDBG("Waiting for response");
			if (select(session->sock + 1, &readFds, NULL, NULL, &timeout) == 0) {
				SDPERR("Client timed out");
				errno = ETIMEDOUT;
				return -1;
			}
			return recv(session->sock, buf, size, 0);
		}

		if (reqhdr->tid != rsphdr->tid) {
			t->err = EPROTO;
			SDPERR("Protocol error: transaction id does not match");
			goto end;
		}

		if (n != (int) (ntohs(rsphdr->plen) + sizeof(sdp_pdu_hdr_t))) {
			t->err = EPROTO;
			SDPERR("Protocol error: invalid length");
			goto end;
		}

		pdu_id = rsphdr->pdu_id;
		switch (rsphdr->pdu_id) {
		uint8_t *ssr_pdata;
		uint16_t tsrc, csrc;
		case SDP_SVC_SEARCH_RSP:
			/*
			 * TSRC: Total Service Record Count (2 bytes)
			 * CSRC: Current Service Record Count (2 bytes)
			 */
			ssr_pdata = pdata;
			tsrc = bt_get_be16(ssr_pdata);
			ssr_pdata += sizeof(uint16_t);
			csrc = bt_get_be16(ssr_pdata);

			/* csrc should never be larger than tsrc */
			if (csrc > tsrc) {
				t->err = EPROTO;
				SDPERR("Protocol error: wrong current service record count value.");
				goto end;
			}

			SDPDBG("Total svc count: %d", tsrc);
			SDPDBG("Current svc count: %d", csrc);

			/* parameter length without continuation state */
			plen = sizeof(tsrc) + sizeof(csrc) + csrc * 4;

			if (t->rsp_concat_buf.data_size == 0) {
				/* first fragment */
				rsp_count = sizeof(tsrc) + sizeof(csrc) + csrc * 4;
			} else if (t->rsp_concat_buf.data_size >= sizeof(uint16_t) * 2) {
				/* point to the first csrc */
				uint8_t *pcsrc = t->rsp_concat_buf.data + 2;
				uint16_t tcsrc, tcsrc2;

				/* FIXME: update the interface later. csrc doesn't need be passed to clients */

				pdata += sizeof(uint16_t); /* point to csrc */

				/* the first csrc contains the sum of partial csrc responses */
				memcpy(&tcsrc, pcsrc, sizeof(tcsrc));
				memcpy(&tcsrc2, pdata, sizeof(tcsrc2));
				tcsrc += tcsrc2;
				memcpy(pcsrc, &tcsrc, sizeof(tcsrc));

				pdata += sizeof(uint16_t); /* point to the first handle */
				rsp_count = csrc * 4;
			} else {
				t->err = EPROTO;
				SDPERR("Protocol error: invalid PDU size");
				status = SDP_INVALID_PDU_SIZE;
				goto end;
			}
			status = 0x0000;
			break;
		case SDP_SVC_ATTR_RSP:
		case SDP_SVC_SEARCH_ATTR_RSP:
			rsp_count = bt_get_be16(pdata);
			SDPDBG("Attrlist byte count : %d", rsp_count);
			//Attrlist byte count : 36

			/* Valid range for rsp_count is 0x0002-0xFFFF */
			if (t->rsp_concat_buf.data_size == 0 && rsp_count < 0x0002) {
				t->err = EPROTO;
				SDPERR("Protocol error: invalid AttrList size");
				status = SDP_INVALID_PDU_SIZE;
				goto end;
			}

			/*
			 * Number of bytes in the AttributeLists parameter(without
			 * continuation state) + AttributeListsByteCount field size.
			 */
			plen = sizeof(uint16_t) + rsp_count;

			pdata += sizeof(uint16_t); /* points to attribute list */
			status = 0x0000;
			break;
		case SDP_ERROR_RSP:
			status = bt_get_be16(pdata);
			size = ntohs(rsphdr->plen);

			goto end;
		default:
			t->err = EPROTO;
			SDPERR("Illegal PDU ID: 0x%x", rsphdr->pdu_id);
			goto end;
		}

		/* Out of bound check before using rsp_count as offset for
		 * continuation state, which has at least a one byte size
		 * field.
		 */
		if ((n - (int) sizeof(sdp_pdu_hdr_t)) < plen + 1) {
			t->err = EPROTO;
			SDPERR("Protocol error: invalid PDU size");
			status = SDP_INVALID_PDU_SIZE;
			goto end;
		}

		pcstate = (sdp_cstate_t *) (pdata + rsp_count);

		SDPDBG("Cstate length : %d", pcstate->length);
		//Cstate length : 2

		/*
		 * Check out of bound. Continuation state must have at least
		 * 1 byte: ZERO to indicate that it is not a partial response.
		 */
		if ((n - (int) sizeof(sdp_pdu_hdr_t))  != (plen + pcstate->length + 1)) {
			t->err = EPROTO;
			SDPERR("Protocol error: wrong PDU size.");
			status = 0xffff;
			goto end;
		}

		/*
		 * This is a split response, need to concatenate intermediate
		 * responses and the last one which will have cstate length == 0
		 */
		t->rsp_concat_buf.data = realloc(t->rsp_concat_buf.data, t->rsp_concat_buf.data_size + rsp_count);
		targetPtr = t->rsp_concat_buf.data + t->rsp_concat_buf.data_size;
		t->rsp_concat_buf.buf_size = t->rsp_concat_buf.data_size + rsp_count;
		memcpy(targetPtr, pdata, rsp_count);
		t->rsp_concat_buf.data_size += rsp_count;

		if (pcstate->length > 0) { //
			int reqsize, cstate_len;

			reqhdr->tid = htons(sdp_gen_tid(session));

			/* add continuation state */
			cstate_len = copy_cstate(t->reqbuf + t->reqsize,
					SDP_REQ_BUFFER_SIZE - t->reqsize, pcstate);

			reqsize = t->reqsize + cstate_len;

			/* set the request header's param length */
			reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));

			if (sdp_send_req(session, t->reqbuf, reqsize) < 0) {
				SDPERR("Error sending data:%m(%d)", errno);
				status = 0xffff;
				t->err = errno;
				goto end;
			}
			err = 0;
		}

	end:
		if (err) {
			if (t->rsp_concat_buf.data_size != 0) {
				pdata = t->rsp_concat_buf.data;
				size = t->rsp_concat_buf.data_size;
			}
			if (t->cb)
				t->cb(pdu_id, status, pdata, size, t->udata);
		}

		free(rspbuf);

		return err;
	}

	return TRUE; //
}

//多轮的search_process_cb()执行后:
search_completed_cb
static void search_completed_cb(uint8_t type, uint16_t status,
			uint8_t *rsp, size_t size, void *user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct search_context *ctxt = user_data;
	sdp_list_t *recs = NULL;
	int scanned, seqlen = 0, bytesleft = size;
	uint8_t dataType;
	int err = 0;

	if (status || type != SDP_SVC_SEARCH_ATTR_RSP) {
		err = -EPROTO;
		goto done;
	}

	scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen);
	if (!scanned || !seqlen)
		goto done;
	int sdp_extract_seqtype(const uint8_t *buf, int bufsize, uint8_t *dtdp, int *size)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		uint8_t dtd;
		int scanned = sizeof(uint8_t);

		if (bufsize < (int) sizeof(uint8_t)) {
			SDPERR("Unexpected end of packet");
			return 0;
		}

		dtd = *(uint8_t *) buf;
		buf += sizeof(uint8_t);
		bufsize -= sizeof(uint8_t);
		*dtdp = dtd;
		switch (dtd) {
		case SDP_SEQ8:
		case SDP_ALT8:
			if (bufsize < (int) sizeof(uint8_t)) {
				SDPERR("Unexpected end of packet");
				return 0;
			}
			*size = *(uint8_t *) buf;
			scanned += sizeof(uint8_t);
			break;
		case SDP_SEQ16:
		case SDP_ALT16:
			if (bufsize < (int) sizeof(uint16_t)) {
				SDPERR("Unexpected end of packet");
				return 0;
			}
			*size = bt_get_be16(buf);
			scanned += sizeof(uint16_t);
			break;
		case SDP_SEQ32:
		case SDP_ALT32:
			if (bufsize < (int) sizeof(uint32_t)) {
				SDPERR("Unexpected end of packet");
				return 0;
			}
			*size = bt_get_be32(buf);
			scanned += sizeof(uint32_t);
			break;
		default:
			SDPERR("Unknown sequence type, aborting");
			return 0;
		}
		return scanned;
	}

	rsp += scanned;
	bytesleft -= scanned;
	do {
		sdp_record_t *rec;
		int recsize;

		recsize = 0;
		rec = sdp_extract_pdu(rsp, bytesleft, &recsize);
		if (!rec)
			break;
		sdp_record_t *sdp_extract_pdu(const uint8_t *buf, int bufsize, int *scanned)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			int extracted = 0, seqlen = 0;
			uint8_t dtd;
			uint16_t attr;
			const uint8_t *p = buf;
			sdp_record_t *rec = sdp_record_alloc();
			sdp_record_t *sdp_record_alloc(void)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				sdp_record_t *rec = malloc(sizeof(sdp_record_t));

				if (!rec)
					return NULL;

				memset(rec, 0, sizeof(sdp_record_t));
				rec->handle = 0xffffffff;
				return rec;
			}

			*scanned = sdp_extract_seqtype(buf, bufsize, &dtd, &seqlen);
			p += *scanned;
			bufsize -= *scanned;
			rec->attrlist = NULL;

			while (extracted < seqlen && bufsize > 0) {
				int n = sizeof(uint8_t), attrlen = 0;
				sdp_data_t *data = NULL;

				SDPDBG("Extract PDU, sequenceLength: %d localExtractedLength: %d",seqlen, extracted);
				//Extract PDU, sequenceLength: 62 localExtractedLength: 0

				if (bufsize < n + (int) sizeof(uint16_t)) {
					SDPERR("Unexpected end of packet");
					break;
				}

				dtd = *(uint8_t *) p;
				attr = bt_get_be16(p + n);
				n += sizeof(uint16_t);

				SDPDBG("DTD of attrId : %d Attr id : 0x%x ", dtd, attr);
				//DTD of attrId : 9 Attr id : 0x0 

				data = sdp_extract_attr(p + n, bufsize - n, &attrlen, rec);
				sdp_data_t *sdp_extract_attr(const uint8_t *p, int bufsize, int *size,
											sdp_record_t *rec)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					sdp_data_t *elem;
					int n = 0;
					uint8_t dtd;

					if (bufsize < (int) sizeof(uint8_t)) {
						SDPERR("Unexpected end of packet");
						return NULL;
					}

					dtd = *(const uint8_t *)p;

					SDPDBG("extract_attr: dtd=0x%x", dtd);
					//extract_attr: dtd=0xa

					switch (dtd) {
					case SDP_DATA_NIL:
					case SDP_BOOL:
					case SDP_UINT8:
					case SDP_UINT16:
					case SDP_UINT32:
					case SDP_UINT64:
					case SDP_UINT128:
					case SDP_INT8:
					case SDP_INT16:
					case SDP_INT32:
					case SDP_INT64:
					case SDP_INT128:
						elem = extract_int(p, bufsize, &n);
						static sdp_data_t *extract_int(const void *p, int bufsize, int *len)
						{
							printf("jokerb %s:in %d.\n",__func__,__LINE__);
							sdp_data_t *d;

							if (bufsize < (int) sizeof(uint8_t)) {
								SDPERR("Unexpected end of packet");
								return NULL;
							}

							d = malloc(sizeof(sdp_data_t));
							if (!d)
								return NULL;

							SDPDBG("Extracting integer");
							memset(d, 0, sizeof(sdp_data_t));
							d->dtd = *(uint8_t *) p;
							p += sizeof(uint8_t);
							*len += sizeof(uint8_t);
							bufsize -= sizeof(uint8_t);

							switch (d->dtd) {
							case SDP_DATA_NIL:
								break;
							case SDP_BOOL:
							case SDP_INT8:
							case SDP_UINT8:
								if (bufsize < (int) sizeof(uint8_t)) {
									SDPERR("Unexpected end of packet");
									free(d);
									return NULL;
								}
								*len += sizeof(uint8_t);
								d->val.uint8 = *(uint8_t *) p;
								break;
							case SDP_INT16:
							case SDP_UINT16:
								if (bufsize < (int) sizeof(uint16_t)) {
									SDPERR("Unexpected end of packet");
									free(d);
									return NULL;
								}
								*len += sizeof(uint16_t);
								d->val.uint16 = bt_get_be16(p);
								break;
							case SDP_INT32:
							case SDP_UINT32:
								if (bufsize < (int) sizeof(uint32_t)) {
									SDPERR("Unexpected end of packet");
									free(d);
									return NULL;
								}
								*len += sizeof(uint32_t);
								d->val.uint32 = bt_get_be32(p);
								break;
							case SDP_INT64:
							case SDP_UINT64:
								if (bufsize < (int) sizeof(uint64_t)) {
									SDPERR("Unexpected end of packet");
									free(d);
									return NULL;
								}
								*len += sizeof(uint64_t);
								d->val.uint64 = bt_get_be64(p);
								break;
							case SDP_INT128:
							case SDP_UINT128:
								if (bufsize < (int) sizeof(uint128_t)) {
									SDPERR("Unexpected end of packet");
									free(d);
									return NULL;
								}
								*len += sizeof(uint128_t);
								ntoh128((uint128_t *) p, &d->val.uint128);
								break;
							default:
								free(d);
								d = NULL;
							}
							return d;
						}
						break;
					case SDP_UUID16:
					case SDP_UUID32:
					case SDP_UUID128:
						elem = extract_uuid(p, bufsize, &n, rec);
						break;
					case SDP_TEXT_STR8:
					case SDP_TEXT_STR16:
					case SDP_TEXT_STR32:
					case SDP_URL_STR8:
					case SDP_URL_STR16:
					case SDP_URL_STR32:
						elem = extract_str(p, bufsize, &n);
						break;
					case SDP_SEQ8:
					case SDP_SEQ16:
					case SDP_SEQ32:
					case SDP_ALT8:
					case SDP_ALT16:
					case SDP_ALT32:
						elem = extract_seq(p, bufsize, &n, rec);
						break;
					default:
						SDPERR("Unknown data descriptor : 0x%x terminating", dtd);
						return NULL;
					}
					*size += n;
					return elem;
				}

				SDPDBG("Attr id : 0x%x attrValueLength : %d", attr, attrlen);
				//Attr id : 0x0 attrValueLength : 5

				n += attrlen;
				if (data == NULL) {
					SDPDBG("Terminating extraction of attributes");
					break;
				}

				if (attr == SDP_ATTR_RECORD_HANDLE)
					rec->handle = data->val.uint32;

				if (attr == SDP_ATTR_SVCLASS_ID_LIST)
					extract_svclass_uuid(data, &rec->svclass);

				extracted += n;
				p += n;
				bufsize -= n;
				sdp_attr_replace(rec, attr, data);
				void sdp_attr_replace(sdp_record_t *rec, uint16_t attr, sdp_data_t *d)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					sdp_data_t *p;

					if (!rec)
						return;

					p = sdp_data_get(rec, attr);
					if (p) {
						rec->attrlist = sdp_list_remove(rec->attrlist, p);
						sdp_data_free(p);
					}
					sdp_data_t *sdp_data_get(const sdp_record_t *rec, uint16_t attrId)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						if (rec && rec->attrlist) {
							sdp_data_t sdpTemplate;
							sdp_list_t *p;

							sdpTemplate.attrId = attrId;
							p = sdp_list_find(rec->attrlist, &sdpTemplate, sdp_attrid_comp_func);
							if (p)
								return p->data;
						}
						return NULL;
					}

					d->attrId = attr;
					rec->attrlist = sdp_list_insert_sorted(rec->attrlist, d, sdp_attrid_comp_func);
					sdp_list_t *sdp_list_insert_sorted(sdp_list_t *list, void *d,
												sdp_comp_func_t f)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						sdp_list_t *q, *p, *n;

						n = malloc(sizeof(sdp_list_t));
						if (!n)
							return NULL;
						n->data = d;
						for (q = 0, p = list; p; q = p, p = p->next)
							if (f(p->data, d) >= 0)
								break;
						/* insert between q and p; if !q insert at head */
						if (q)
							q->next = n;
						else
							list = n;
						n->next = p;
						return list;
					}

					if (attr == SDP_ATTR_SVCLASS_ID_LIST)
						extract_svclass_uuid(d, &rec->svclass);
				}

				SDPDBG("Extract PDU, seqLength: %d localExtractedLength: %d",seqlen, extracted);
				//Extract PDU, seqLength: 62 localExtractedLength: 8
			}
#ifdef SDP_DEBUG
			SDPDBG("Successful extracting of Svc Rec attributes");
			sdp_print_service_attr(rec->attrlist);
			void sdp_print_service_attr(sdp_list_t *svcAttrList)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				SDPDBG("Printing service attr list %p", svcAttrList);
				sdp_list_foreach(svcAttrList, attr_print_func, NULL);
				SDPDBG("Printed service attr list %p", svcAttrList);
					attr_print_func: =====================================
					 attr_print_func: ATTRIBUTE IDENTIFIER : 0x0
					 attr_print_func: ATTRIBUTE VALUE PTR : 0x1173a8
					 sdp_data_print: Integer : 0x2
					 attr_print_func: =====================================
					 attr_print_func: =====================================
					 attr_print_func: ATTRIBUTE IDENTIFIER : 0x1
					 attr_print_func: ATTRIBUTE VALUE PTR : 0x1164e8
					 sdp_data_print: UUID
					 sdp_uuid_print:   uint16_t : 0x111e
					 sdp_data_print: UUID
					 sdp_uuid_print:   uint16_t : 0x1203
					 attr_print_func: =====================================
					 attr_print_func: =====================================
					 attr_print_func: ATTRIBUTE IDENTIFIER : 0x4
					 attr_print_func: ATTRIBUTE VALUE PTR : 0x11f6e8
					 sdp_data_print: UUID
					 sdp_uuid_print:   uint16_t : 0x0100
					 sdp_data_print: UUID
					 sdp_uuid_print:   uint16_t : 0x0003
					 sdp_data_print: Integer : 0x4
					 attr_print_func: =====================================
					 attr_print_func: =====================================
					 attr_print_func: ATTRIBUTE IDENTIFIER : 0x9
					 attr_print_func: ATTRIBUTE VALUE PTR : 0x117210
					 sdp_data_print: UUID
					 sdp_uuid_print:   uint16_t : 0x111e
					 sdp_data_print: Integer : 0x108
					 attr_print_func: =====================================
					 attr_print_func: =====================================
					 attr_print_func: ATTRIBUTE IDENTIFIER : 0x100
					 attr_print_func: ATTRIBUTE VALUE PTR : 0x117738
					 sdp_data_print: Text : HF
					 attr_print_func: =====================================
					 attr_print_func: =====================================
					 attr_print_func: ATTRIBUTE IDENTIFIER : 0x311
					 attr_print_func: ATTRIBUTE VALUE PTR : 0x1173f0
					 sdp_data_print: Integer : 0x3f
					 attr_print_func: =====================================
					 sdp_print_service_attr: Printed service attr list 0x1179e0

					attr_print_func: =====================================
					attr_print_func: ATTRIBUTE IDENTIFIER : 0x0
					attr_print_func: ATTRIBUTE VALUE PTR : 0x117b30
					jokerb sdp_data_print:in 1657.
					sdp_data_print: Integer : 0x3
					attr_print_func: =====================================
					jokerb attr_print_func:in 1405.
					attr_print_func: =====================================
					attr_print_func: ATTRIBUTE IDENTIFIER : 0x1
					attr_print_func: ATTRIBUTE VALUE PTR : 0x1113c0
					jokerb sdp_data_print:in 1657.
					jokerb print_dataseq:in 1632.
					jokerb sdp_data_print:in 1657.
					sdp_data_print: UUID
					sdp_uuid_print:   uint16_t : 0x110b
					attr_print_func: =====================================
					jokerb attr_print_func:in 1405.
					attr_print_func: =====================================
					attr_print_func: ATTRIBUTE IDENTIFIER : 0x4
					attr_print_func: ATTRIBUTE VALUE PTR : 0x11eb40

attr_print_func: =====================================
jokerb attr_print_func:in 1405.
attr_print_func: =====================================
attr_print_func: ATTRIBUTE IDENTIFIER : 0x9
attr_print_func: ATTRIBUTE VALUE PTR : 0x116f28
jokerb sdp_data_print:in 1657.
jokerb print_dataseq:in 1632.
jokerb sdp_data_print:in 1657.
jokerb print_dataseq:in 1632.
jokerb sdp_data_print:in 1657.
sdp_data_print: UUID
sdp_uuid_print:   uint16_t : 0x110d
jokerb sdp_data_print:in 1657.
sdp_data_print: Integer : 0x103
attr_print_func: =====================================
jokerb attr_print_func:in 1405.
attr_print_func: =====================================
attr_print_func: ATTRIBUTE IDENTIFIER : 0x100
attr_print_func: ATTRIBUTE VALUE PTR : 0x112e30
jokerb sdp_data_print:in 1657.
sdp_data_print: Text : Aud-Snk
attr_print_func: =====================================
jokerb attr_print_func:in 1405.
attr_print_func: =====================================
attr_print_func: ATTRIBUTE IDENTIFIER : 0x311
attr_print_func: ATTRIBUTE VALUE PTR : 0x11f000
jokerb sdp_data_print:in 1657.
sdp_data_print: Integer : 0x3
attr_print_func: =====================================
sdp_print_service_attr: Printed service attr list 0x115e10

ttr_print_func: =====================================
attr_print_func: ATTRIBUTE IDENTIFIER : 0x0
attr_print_func: ATTRIBUTE VALUE PTR : 0x11f030
jokerb sdp_data_print:in 1657.
sdp_data_print: Integer : 0x4
attr_print_func: =====================================
jokerb attr_print_func:in 1405.
attr_print_func: =====================================
attr_print_func: ATTRIBUTE IDENTIFIER : 0x1
attr_print_func: ATTRIBUTE VALUE PTR : 0x117d20
jokerb sdp_data_print:in 1657.
jokerb print_dataseq:in 1632.
jokerb sdp_data_print:in 1657.
sdp_data_print: UUID
sdp_uuid_print:   uint16_t : 0x110e
jokerb sdp_data_print:in 1657.
sdp_data_print: UUID
sdp_uuid_print:   uint16_t : 0x110f
attr_print_func: =====================================
jokerb attr_print_func:in 1405.
attr_print_func: =====================================
attr_print_func: ATTRIBUTE IDENTIFIER : 0x4
attr_print_func: ATTRIBUTE VALUE PTR : 0x112408

attr_print_func: =====================================
jokerb attr_print_func:in 1405.
attr_print_func: =====================================
attr_print_func: ATTRIBUTE IDENTIFIER : 0x9
attr_print_func: ATTRIBUTE VALUE PTR : 0x11eaa8
jokerb sdp_data_print:in 1657.
jokerb print_dataseq:in 1632.
jokerb sdp_data_print:in 1657.
jokerb print_dataseq:in 1632.
jokerb sdp_data_print:in 1657.
sdp_data_print: UUID
sdp_uuid_print:   uint16_t : 0x110e
jokerb sdp_data_print:in 1657.
sdp_data_print: Integer : 0x106
attr_print_func: =====================================
jokerb attr_print_func:in 1405.
attr_print_func: =====================================
attr_print_func: ATTRIBUTE IDENTIFIER : 0x100
attr_print_func: ATTRIBUTE VALUE PTR : 0x116e70
jokerb sdp_data_print:in 1657.
sdp_data_print: Text : AVRCP-CT
attr_print_func: =====================================
jokerb attr_print_func:in 1405.
attr_print_func: =====================================
attr_print_func: ATTRIBUTE IDENTIFIER : 0x311
attr_print_func: ATTRIBUTE VALUE PTR : 0x116ec0
jokerb sdp_data_print:in 1657.
sdp_data_print: Integer : 0x1
attr_print_func: =====================================
sdp_print_service_attr: Printed service attr list 0x112e60
			}
#endif
			*scanned += seqlen;
			return rec;
		}

		if (!recsize) {
			sdp_record_free(rec);
			break;
		}

		scanned += recsize;
		rsp += recsize;
		bytesleft -= recsize;

		recs = sdp_list_append(recs, rec);
		sdp_list_t *sdp_list_append(sdp_list_t *p, void *d)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			sdp_list_t *q, *n = malloc(sizeof(sdp_list_t));

			if (!n)
				return NULL;

			n->data = d;
			n->next = 0;

			if (!p)
				return n;

			for (q = p; q->next; q = q->next);
			q->next = n;

			return p;
		}
	} while (scanned < (ssize_t) size && bytesleft > 0);

done:
	cache_sdp_session(&ctxt->src, &ctxt->dst, ctxt->session);
	static void cache_sdp_session(bdaddr_t *src, bdaddr_t *dst,
							sdp_session_t *session)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct cached_sdp_session *cached;
		int sk;
		GIOChannel *chan;

		cached = g_new0(struct cached_sdp_session, 1);

		bacpy(&cached->src, src);
		bacpy(&cached->dst, dst);

		cached->session = session;

		cached_sdp_sessions = g_slist_append(cached_sdp_sessions, cached);

		/*cached->timer = g_timeout_add_seconds(CACHE_TIMEOUT,
							cached_session_expired,
							cached);*/

		/* Watch the connection state during cache timeout */
		sk = sdp_get_socket(session);
		int sdp_get_socket(const sdp_session_t *session)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			return session->sock;
		}
		chan = g_io_channel_unix_new(sk);

		cached->io_id = g_io_add_watch(chan, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
							disconnect_watch, cached);

		DBG("call channel unref\n");
		g_io_channel_unref(chan);
	}

	if (ctxt->cb)
		ctxt->cb(recs, err, ctxt->user_data);

	if (recs)
		sdp_list_free(recs, (sdp_free_func_t) sdp_record_free);

	search_context_cleanup(ctxt);
}

//执行完search_completed_cb()后, browse_cb就执行了.
browse_cb
static void browse_cb(sdp_list_t *recs, int err, gpointer user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct browse_req *req = user_data; <tag70>
	struct btd_device *device = req->device;
	struct btd_adapter *adapter = device->adapter;
	uuid_t uuid;

    DBG("");
	/* If we have a valid response and req->search_uuid == 2, then L2CAP
	 * UUID & PNP searching was successful -- we are done */
	if (err < 0 || (req->search_uuid == 2 && req->records)) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		if (err == -ECONNRESET && req->reconnect_attempt < 1) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			req->search_uuid--;
			req->reconnect_attempt++;
		} else {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			goto done;
		}
	}

	update_bredr_services(req, recs);
	static void update_bredr_services(struct browse_req *req, sdp_list_t *recs)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct btd_device *device = req->device;
		sdp_list_t *seq;
		char srcaddr[18], dstaddr[18];
		char sdp_file[PATH_MAX];
		char att_file[PATH_MAX];
		GKeyFile *sdp_key_file;
		GKeyFile *att_key_file;
		char *data;
		gsize length = 0;

		ba2str(btd_adapter_get_address(device->adapter), srcaddr);
		ba2str(&device->bdaddr, dstaddr);

		snprintf(sdp_file, PATH_MAX, STORAGEDIR "/%s/cache/%s", srcaddr,dstaddr);
		printf("jokerb %s:in %d.sdp_file %s\n",__func__,__LINE__, sdp_file);
		//sdp_file /userdata/lib/bluetooth/68:89:5B:01:28:23/cache/04:57:91:CC:BB:0E

		sdp_key_file = g_key_file_new();
		g_key_file_load_from_file(sdp_key_file, sdp_file, 0, NULL);

		snprintf(att_file, PATH_MAX, STORAGEDIR "/%s/%s/attributes", srcaddr,dstaddr);
		printf("jokerb %s:in %d.att_file %s\n",__func__,__LINE__, att_file);
		//att_file /userdata/lib/bluetooth/68:89:5B:01:28:23/04:57:91:CC:BB:0E/attributes

		att_key_file = g_key_file_new();
		g_key_file_load_from_file(att_key_file, att_file, 0, NULL);

		//sdp_list_t *recs
		for (seq = recs; seq; seq = seq->next) { //GM into 3 times
			printf("jokerb %s:in %d.\n",__func__,__LINE__);//
			sdp_record_t *rec = (sdp_record_t *) seq->data;
			sdp_list_t *svcclass = NULL;
			char *profile_uuid;

			if (!rec) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				break;
			}

			if (sdp_get_service_classes(rec, &svcclass) < 0) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				continue;
			}
			static inline int sdp_get_service_classes(const sdp_record_t *rec, sdp_list_t **seqp)
			{
				return sdp_get_uuidseq_attr(rec, SDP_ATTR_SVCLASS_ID_LIST, seqp);
				int sdp_get_uuidseq_attr(const sdp_record_t *rec, uint16_t attr,sdp_list_t **seqp)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					sdp_data_t *sdpdata = sdp_data_get(rec, attr);
					sdp_data_t *sdp_data_get(const sdp_record_t *rec, uint16_t attrId)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						if (rec && rec->attrlist) {
							sdp_data_t sdpTemplate;
							sdp_list_t *p;

							sdpTemplate.attrId = attrId;
							p = sdp_list_find(rec->attrlist, &sdpTemplate, sdp_attrid_comp_func);
							if (p)
								return p->data;
							int sdp_attrid_comp_func(const void *key1, const void *key2)//Gm run 2
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								const sdp_data_t *d1 = (const sdp_data_t *)key1;
								const sdp_data_t *d2 = (const sdp_data_t *)key2;

								if (d1 && d2)
									return d1->attrId - d2->attrId;
								return 0;
							}
							static inline sdp_list_t *sdp_list_find(sdp_list_t *list, void *u, sdp_comp_func_t f)
							{
								for (; list; list = list->next)
									if (f(list->data, u) == 0)
										return list;
								return NULL;
							}
						}
						return NULL;
					}

					*seqp = NULL;
					if (sdpdata && SDP_IS_SEQ(sdpdata->dtd)) {
						sdp_data_t *d;
						for (d = sdpdata->val.dataseq; d; d = d->next) {
							uuid_t *u;
							if (d->dtd < SDP_UUID16 || d->dtd > SDP_UUID128) {
								errno = EINVAL;
								goto fail;
							}

							u = malloc(sizeof(uuid_t));
							if (!u)
								goto fail;

							*u = d->val.uuid;
							*seqp = sdp_list_append(*seqp, u); // GM run 2 times
						}
						return 0;
					}
				fail:
					sdp_list_free(*seqp, free);
					*seqp = NULL;
					return -1;
				}
			}

			/* Check for empty service classes list */
			if (svcclass == NULL) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				DBG("Skipping record with no service classes");
				continue;
			}

			/* Extract the first element and skip the remainning */
			profile_uuid = bt_uuid2string(svcclass->data);
			if (!profile_uuid) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				sdp_list_free(svcclass, free);
				continue;
			}
			char *bt_uuid2string(uuid_t *uuid)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				char *str;
				uuid_t uuid128;
				unsigned int data0;
				unsigned short data1;
				unsigned short data2;
				unsigned short data3;
				unsigned int data4;
				unsigned short data5;
				int err;

				if (!uuid)
					return NULL;

				switch (uuid->type) {
				case SDP_UUID16:
					sdp_uuid16_to_uuid128(&uuid128, uuid);
					void sdp_uuid16_to_uuid128(uuid_t *uuid128, const uuid_t *uuid16)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						/*
						 * We have a 16 bit value, which needs to be added to
						 * bytes 3 and 4 (at indices 2 and 3) of the Bluetooth base
						 */
						unsigned short data1;

						/* allocate a 128bit UUID and init to the Bluetooth base UUID */
						uuid128->value.uuid128 = bluetooth_base_uuid;
						uuid128->type = SDP_UUID128;

						/* extract bytes 2 and 3 of 128bit BT base UUID */
						memcpy(&data1, &bluetooth_base_uuid.data[2], 2);

						/* add the given UUID (16 bits) */
						data1 += htons(uuid16->value.uuid16);

						/* set bytes 2 and 3 of the 128 bit value */
						memcpy(&uuid128->value.uuid128.data[2], &data1, 2);
					}
					break;
				case SDP_UUID32:
					sdp_uuid32_to_uuid128(&uuid128, uuid);
					break;
				case SDP_UUID128:
					memcpy(&uuid128, uuid, sizeof(uuid_t));
					break;
				default:
					/* Type of UUID unknown */
					return NULL;
				}

				memcpy(&data0, &uuid128.value.uuid128.data[0], 4);
				memcpy(&data1, &uuid128.value.uuid128.data[4], 2);
				memcpy(&data2, &uuid128.value.uuid128.data[6], 2);
				memcpy(&data3, &uuid128.value.uuid128.data[8], 2);
				memcpy(&data4, &uuid128.value.uuid128.data[10], 4);
				memcpy(&data5, &uuid128.value.uuid128.data[14], 2);

				err = asprintf(&str, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
						ntohl(data0), ntohs(data1),
						ntohs(data2), ntohs(data3),
						ntohl(data4), ntohs(data5));
				if (err < 0)
					return NULL;

				return str;
			}

			if (bt_uuid_strcmp(profile_uuid, PNP_UUID) == 0) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				uint16_t source, vendor, product, version;
				sdp_data_t *pdlist;

				pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID_SOURCE);
				source = pdlist ? pdlist->val.uint16 : 0x0000;

				pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID);
				vendor = pdlist ? pdlist->val.uint16 : 0x0000;

				pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID);
				product = pdlist ? pdlist->val.uint16 : 0x0000;

				pdlist = sdp_data_get(rec, SDP_ATTR_VERSION);
				version = pdlist ? pdlist->val.uint16 : 0x0000;

				if (source || vendor || product || version) {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					btd_device_set_pnpid(device, source, vendor,
								product, version);
				}
			}

			if (update_record(req, profile_uuid, rec) < 0) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				goto next;
			}
			static int update_record(struct browse_req *req, const char *uuid,
										sdp_record_t *rec)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				GSList *l;

				/* Check for duplicates */
				if (sdp_list_find(req->records, rec, rec_cmp))
					return -EALREADY;

				/* Copy record */
				req->records = sdp_list_append(req->records, sdp_copy_record(rec)); <tag71>
				sdp_record_t *sdp_copy_record(sdp_record_t *rec)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					sdp_record_t *cpy;

					cpy = sdp_record_alloc();

					cpy->handle = rec->handle;

					sdp_list_foreach(rec->pattern, sdp_copy_pattern, cpy);
					sdp_list_foreach(rec->attrlist, sdp_copy_attrlist, cpy);

					cpy->svclass = rec->svclass;

					return cpy;
				}

				/* Check if UUID is duplicated */
				l = g_slist_find_custom(req->device->uuids, uuid, bt_uuid_strcmp);
				if (l == NULL) {
					l = g_slist_find_custom(req->profiles_added, uuid,
										bt_uuid_strcmp);
					if (l != NULL)
						return 0;
					req->profiles_added = g_slist_append(req->profiles_added,
										g_strdup(uuid)); <tag74>
				}

				return 0;
			}

			if (sdp_key_file) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__); //
				store_sdp_record(sdp_key_file, rec);
				static void store_sdp_record(GKeyFile *key_file, sdp_record_t *rec)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					char handle_str[11];
					sdp_buf_t buf;
					int size, i;
					char *str;

					sprintf(handle_str, "0x%8.8X", rec->handle);

					if (sdp_gen_record_pdu(rec, &buf) < 0)
						return;

					size = buf.data_size;

					str = g_malloc0(size*2+1);

					for (i = 0; i < size; i++)
						sprintf(str + (i * 2), "%02X", buf.data[i]);

					g_key_file_set_string(key_file, "ServiceRecords", handle_str, str);

					free(buf.data);
					g_free(str);
				}
			}

			if (att_key_file) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__); //
				store_primaries_from_sdp_record(att_key_file, rec);
				static void store_primaries_from_sdp_record(GKeyFile *key_file,sdp_record_t *rec)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					uuid_t uuid;
					char *att_uuid, *prim_uuid;
					uint16_t start = 0, end = 0, psm = 0;
					char handle[6], uuid_str[33];
					int i;

					sdp_uuid16_create(&uuid, ATT_UUID);
					att_uuid = bt_uuid2string(&uuid);

					sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
					prim_uuid = bt_uuid2string(&uuid);

					if (!record_has_uuid(rec, att_uuid))
						goto done;

					if (!gatt_parse_record(rec, &uuid, &psm, &start, &end))
						goto done;

					sprintf(handle, "%hu", start);
					switch (uuid.type) {
					case SDP_UUID16:
						sprintf(uuid_str, "%4.4X", uuid.value.uuid16);
						break;
					case SDP_UUID32:
						sprintf(uuid_str, "%8.8X", uuid.value.uuid32);
						break;
					case SDP_UUID128:
						for (i = 0; i < 16; i++)
							sprintf(uuid_str + (i * 2), "%2.2X",
									uuid.value.uuid128.data[i]);
						break;
					default:
						uuid_str[0] = '\0';
					}

					g_key_file_set_string(key_file, handle, "UUID", prim_uuid);
					g_key_file_set_string(key_file, handle, "Value", uuid_str);
					g_key_file_set_integer(key_file, handle, "EndGroupHandle", end);

				done:
					free(prim_uuid);
					free(att_uuid);
				}
			}

	next:
			free(profile_uuid);
			sdp_list_free(svcclass, free);
		}

		if (sdp_key_file) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			data = g_key_file_to_data(sdp_key_file, &length, NULL);
			if (length > 0) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__); //
				create_file(sdp_file, S_IRUSR | S_IWUSR);
				g_file_set_contents(sdp_file, data, length, NULL);
			}

			g_free(data);
			g_key_file_free(sdp_key_file);
		}

		if (att_key_file) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			data = g_key_file_to_data(att_key_file, &length, NULL);
			if (length > 0) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				create_file(att_file, S_IRUSR | S_IWUSR);
				g_file_set_contents(att_file, data, length, NULL);
			}

			g_free(data);
			g_key_file_free(att_key_file);
		}
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
	}

	/* Search for mandatory uuids */
	if (uuid_list[req->search_uuid]) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__); // GM in here
		sdp_uuid16_create(&uuid, uuid_list[req->search_uuid++]);
		bt_search_service(btd_adapter_get_address(adapter),
						&device->bdaddr, &uuid,
						browse_cb, user_data, NULL,
						req->sdp_flags);
		return;
		static void browse_cb(sdp_list_t *recs, int err, gpointer user_data)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			struct browse_req *req = user_data;
			struct btd_device *device = req->device;
			struct btd_adapter *adapter = device->adapter;
			uuid_t uuid;

			DBG("");
			/* If we have a valid response and req->search_uuid == 2, then L2CAP
			 * UUID & PNP searching was successful -- we are done */
			if (err < 0 || (req->search_uuid == 2 && req->records)) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__); //
				if (err == -ECONNRESET && req->reconnect_attempt < 1) {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					req->search_uuid--;
					req->reconnect_attempt++;
				} else {
					printf("jokerb %s:in %d.\n",__func__,__LINE__); //
					goto done;
				}
			}

			update_bredr_services(req, recs);

			/* Search for mandatory uuids */
			if (uuid_list[req->search_uuid]) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				sdp_uuid16_create(&uuid, uuid_list[req->search_uuid++]);
				bt_search_service(btd_adapter_get_address(adapter),
								&device->bdaddr, &uuid,
								browse_cb, user_data, NULL,
								req->sdp_flags);
				return;
			}

		done:
			printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			search_cb(recs, err, user_data);
			static void search_cb(sdp_list_t *recs, int err, gpointer user_data)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct browse_req *req = user_data;
				struct btd_device *device = req->device;
				GSList *primaries;
				char addr[18];

				DBG("");
				ba2str(&device->bdaddr, addr);

				if (err < 0) {
					error("%s: error updating services: %s (%d)",
							addr, strerror(-err), -err);
					goto send_reply;
				}

				update_bredr_services(req, recs);

				if (device->tmp_records) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
					sdp_list_free(device->tmp_records,
								(sdp_free_func_t) sdp_record_free);
				}

				device->tmp_records = req->records; <tag73>
				req->records = NULL;

				if (!req->profiles_added) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
					DBG("%s: No service update", addr);
					goto send_reply;
				}

				primaries = device_services_from_record(device, req->profiles_added);
				if (primaries) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
					device_register_primaries(device, primaries, ATT_PSM);
				}
				static GSList *device_services_from_record(struct btd_device *device,
											GSList *profiles)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					GSList *l, *prim_list = NULL;
					char *att_uuid;
					uuid_t proto_uuid;

					sdp_uuid16_create(&proto_uuid, ATT_UUID);
					att_uuid = bt_uuid2string(&proto_uuid);

					for (l = profiles; l; l = l->next) {
						const char *profile_uuid = l->data;
						const sdp_record_t *rec;
						struct gatt_primary *prim;
						uint16_t start = 0, end = 0, psm = 0;
						uuid_t prim_uuid;

						rec = btd_device_get_record(device, profile_uuid);
						if (!rec)
							continue;

						if (!record_has_uuid(rec, att_uuid))
							continue;

						if (!gatt_parse_record(rec, &prim_uuid, &psm, &start, &end))
							continue;

						prim = g_new0(struct gatt_primary, 1);
						prim->range.start = start;
						prim->range.end = end;
						sdp_uuid2strn(&prim_uuid, prim->uuid, sizeof(prim->uuid));

						prim_list = g_slist_append(prim_list, prim);
					}

					free(att_uuid);

					return prim_list;
				}

				/*
				 * TODO: The btd_service instances for GATT services need to be
				 * initialized with the service handles. Eventually this code should
				 * perform ATT protocol service discovery over the ATT PSM to obtain
				 * the full list of services and populate a client-role gatt_db over
				 * BR/EDR.
				 */
				device_probe_profiles(device, req->profiles_added);
				void device_probe_profiles(struct btd_device *device, GSList *uuids)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct probe_data d = { device, uuids };
					char addr[18];

					ba2str(&device->bdaddr, addr);

					if (device->blocked) {
						DBG("Skipping profiles for blocked device %s", addr);
						goto add_uuids;
					}

					DBG("Probing profiles for device %s", addr);
					//Probing profiles for device 04:57:91:CC:BB:0E

					btd_profile_foreach(dev_probe, &d);
					void btd_profile_foreach(void (*func)(struct btd_profile *p, void *data),
													void *data)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						GSList *l, *next;

						/* GM: 这里遍历了所有profile, 找到匹配的profile */
						for (l = profiles; l != NULL; l = next) {
							struct btd_profile *profile = l->data;
							printf("jokerb %s:in %d. profile %s\n",__func__,__LINE__, profile->name);
							//profile avrcp-controller
							//profile a2dp-sink
							//profile hfp

							next = g_slist_next(l);

							func(profile, data);
							->dev_probe
							static void dev_probe(struct btd_profile *p, void *user_data)
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								struct probe_data *d = user_data;
								struct btd_service *service;

								service = probe_service(d->dev, p, d->uuids);
								if (!service)
									return;
								static struct btd_service *probe_service(struct btd_device *device,
														struct btd_profile *profile,
														GSList *uuids)
								{
									printf("jokerb %s:in %d.\n",__func__,__LINE__);
									struct btd_service *service;

									if (profile->device_probe == NULL)
										return NULL;

									if (!device_match_profile(device, profile, uuids))
										return NULL;

									service = service_create(device, profile);

									if (service_probe(service)) {
										btd_service_unref(service);
										return NULL;
									}
									int service_probe(struct btd_service *service)
									{
										printf("jokerb %s:in %d.\n",__func__,__LINE__);
										char addr[18];
										int err;

										btd_assert(service->state == BTD_SERVICE_STATE_UNAVAILABLE);

										err = service->profile->device_probe(service);
										if (err == 0) {
											change_state(service, BTD_SERVICE_STATE_DISCONNECTED, 0);
											return 0;
										}

										ba2str(device_get_address(service->device), addr);
										error("%s profile probe failed for %s", service->profile->name, addr);

										return err;
									}
									//avrcp_controller_probe
									//a2dp_sink_probe
									//hfp_device_probe

									/* Only set auto connect if profile has set the flag and can really
									 * accept connections.
									 */
									if (profile->auto_connect && profile->accept)
										device_set_auto_connect(device, TRUE);

									return service;
								}

								d->dev->services = g_slist_append(d->dev->services, service); <tag75>
							}
						}

						for (l = ext_profiles; l != NULL; l = next) {
							struct ext_profile *profile = l->data;

							next = g_slist_next(l);

							func(&profile->p, data);
						}
					}

				add_uuids:
					device_add_uuids(device, uuids);
					static void device_add_uuids(struct btd_device *device, GSList *uuids)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						GSList *l;
						bool changed = false;

						for (l = uuids; l != NULL; l = g_slist_next(l)) {
							GSList *match = g_slist_find_custom(device->uuids, l->data,
												bt_uuid_strcmp);
							if (match)
								continue;

							changed = true;
							device->uuids = g_slist_insert_sorted(device->uuids,
											g_strdup(l->data),
											bt_uuid_strcmp);
						}

						if (changed)
							g_dbus_emit_property_changed(dbus_conn, device->path,
											DEVICE_INTERFACE, "UUIDs");
					}
				}

				/* Propagate services changes */
				g_dbus_emit_property_changed(dbus_conn, req->device->path,
									DEVICE_INTERFACE, "UUIDs");

			send_reply:
				device_svc_resolved(device, BROWSE_SDP, BDADDR_BREDR, err);
				static void device_svc_resolved(struct btd_device *dev, uint8_t browse_type,
										uint8_t bdaddr_type, int err)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct bearer_state *state = get_state(dev, bdaddr_type);
					struct browse_req *req = dev->browse;

					DBG("%s err %d", dev->path, err);

					state->svc_resolved = true; <tag77>

					/* Disconnection notification can happen before this function
					 * gets called, so don't set svc_refreshed for a disconnected
					 * device.
					 */
					if (state->connected) {//
						device_set_svc_refreshed(dev, true);
					}
					static void device_set_svc_refreshed(struct btd_device *device, bool value)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						if (device->svc_refreshed == value)
							return;

						DBG("");
						device->svc_refreshed = value;

						g_dbus_emit_property_changed(dbus_conn, device->path,
										DEVICE_INTERFACE, "ServicesResolved");
					}

					g_slist_free_full(dev->eir_uuids, g_free);
					dev->eir_uuids = NULL;

					if (dev->pending_paired) {
						g_dbus_emit_property_changed(dbus_conn, dev->path,
										DEVICE_INTERFACE, "Paired");
						dev->pending_paired = false;
					}

					while (dev->svc_callbacks) {
						struct svc_callback *cb = dev->svc_callbacks->data;

						if (cb->idle_id > 0)
							g_source_remove(cb->idle_id);

						cb->func(dev, err, cb->user_data);

						dev->svc_callbacks = g_slist_delete_link(dev->svc_callbacks,
											dev->svc_callbacks);
						g_free(cb);
					}

					if (!dev->temporary)
						store_device_info(dev);

					if (bdaddr_type != BDADDR_BREDR && err == 0)
						store_services(dev);

					if (!req)
						return;

					browse_request_complete(req, browse_type, bdaddr_type, err);
					static void browse_request_complete(struct browse_req *req, uint8_t type,
											uint8_t bdaddr_type, int err)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						struct btd_device *dev = req->device;
						DBusMessage *reply = NULL;

						if (req->type != type)
							return;

						if (!req->msg)
							goto done;

						if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE, "Pair")) {
							if (!device_is_paired(dev, bdaddr_type)) {
								reply = btd_error_failed(req->msg, "Not paired");
								goto done;
							}

							if (dev->pending_paired) {
								g_dbus_emit_property_changed(dbus_conn, dev->path,
											DEVICE_INTERFACE, "Paired");
								dev->pending_paired = false;
							}

							/* Disregard browse errors in case of Pair */
							reply = g_dbus_create_reply(req->msg, DBUS_TYPE_INVALID);
							goto done;
						}

						if (err) {
							/* Fallback to LE bearer if supported */
							if (err == -EHOSTDOWN && bdaddr_type == BDADDR_BREDR &&
									dev->le && !dev->le_state.connected) {
								err = device_connect_le(dev);
								if (err == 0)
									goto done;
							}
							reply = btd_error_failed(req->msg, strerror(-err));
							goto done;
						}

						if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE, "Connect"))
							reply = dev_connect(dbus_conn, req->msg, dev);
						else if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE,
												"ConnectProfile"))
							reply = connect_profile(dbus_conn, req->msg, dev);
						else
							reply = g_dbus_create_reply(req->msg, DBUS_TYPE_INVALID);

					done:
						if (reply)
							g_dbus_send_message(dbus_conn, reply);

						browse_request_free(req);
					}
				}
				printf("jokerb %s:in %d.\n",__func__,__LINE__); //
			}
		}
	}

done:
	printf("jokerb %s:in %d.\n",__func__,__LINE__); //GM return before, no exec
	search_cb(recs, err, user_data);
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
}

//手动连接. 
//执行 蓝牙设备连接
g_dbus_proxy_call_sync(adapter_proxy, "Connect" ,NULL,G_DBUS_CALL_FLAGS_NONE,-1,NULL,&error)
	=>{ GDBUS_ASYNC_METHOD("Connect", NULL, NULL, dev_connect) }, // src/device.c

static DBusMessage *dev_connect(DBusConnection *conn, DBusMessage *msg, void *user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct btd_device *dev = user_data;
	uint8_t bdaddr_type;

    DBG("enter\n");
	if (dev->bredr_state.connected) {
		/*
		 * Check if services have been resolved and there is at list
		 * one connected before switching to connect LE.
		 */
		if (dev->bredr_state.svc_resolved &&
			find_service_with_state(dev->services,
						BTD_SERVICE_STATE_CONNECTED))
			bdaddr_type = dev->bdaddr_type;
		else
			bdaddr_type = BDADDR_BREDR;
	} else if (dev->le_state.connected && dev->bredr)
		bdaddr_type = BDADDR_BREDR;
	else
		bdaddr_type = select_conn_bearer(dev); // GM: into here

    DBG("bdaddr_type: %d\n", bdaddr_type);
	//bdaddr_type: 0
	//
	if (bdaddr_type != BDADDR_BREDR) { //GM: no into
		int err;

		if (dev->le_state.connected)
			return dbus_message_new_method_return(msg);

		btd_device_set_temporary(dev, false);

		if (dev->disable_auto_connect) {
			dev->disable_auto_connect = FALSE;
			device_set_auto_connect(dev, TRUE);
		}

		err = device_connect_le(dev);
		if (err < 0)
			return btd_error_failed(msg, strerror(-err));

		dev->connect = dbus_message_ref(msg);

		return NULL;
	}

    DBG("call connect profiles\n");
	return connect_profiles(dev, bdaddr_type, msg, NULL);
	static DBusMessage *connect_profiles(struct btd_device *dev, uint8_t bdaddr_type,
						DBusMessage *msg, const char *uuid)
	{
		struct bearer_state *state = get_state(dev, bdaddr_type);
		int err;

		DBG("%s %s, client %s", dev->path, uuid ? uuid : "(all)",
							dbus_message_get_sender(msg));
		///org/bluez/hci0/dev_04_57_91_CC_BB_0E (all), client :1.1

		if (dev->pending || dev->connect || dev->browse) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			DBG("in progress\n");
			return btd_error_in_progress(msg);
		}

		if (!btd_adapter_get_powered(dev->adapter)) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
			DBG("adapter not get power\n");
			return btd_error_not_ready(msg);
		}
		bool btd_adapter_get_powered(struct btd_adapter *adapter)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			if (adapter->current_settings & MGMT_SETTING_POWERED)
				return true;

			return false;
		}

		btd_device_set_temporary(dev, false);
		void btd_device_set_temporary(struct btd_device *device, bool temporary)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			DBG("");
			if (!device)
				return;

			if (device->temporary == temporary)
				return;

			if (device_address_is_private(device))
				return;
			static bool device_address_is_private(struct btd_device *dev)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				if (dev->bdaddr_type != BDADDR_LE_RANDOM)
					return false;

				switch (dev->bdaddr.b[5] >> 6) {
				case 0x00:	/* Private non-resolvable */
				case 0x01:	/* Private resolvable */
					return true;
				default:
					return false;
				}
			}

			DBG("temporary %d", temporary);

			device->temporary = temporary;

			if (temporary) {
				if (device->bredr)
					adapter_whitelist_remove(device->adapter, device);
				adapter_connect_list_remove(device->adapter, device);
				return;
			}

			if (device->bredr)
				adapter_whitelist_add(device->adapter, device);

			store_device_info(device);
		}

		if (!state->svc_resolved) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			goto resolve_services;
		}

		dev->pending = create_pending_list(dev, uuid);
		if (!dev->pending) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			if (dev->svc_refreshed) {
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				if (find_service_with_state(dev->services,
							BTD_SERVICE_STATE_CONNECTED))
					return dbus_message_new_method_return(msg);
				else {
					DBG("not avaliable\n");
					return btd_error_not_available(msg);
				}
			}

			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			goto resolve_services;
		}
		static GSList *create_pending_list(struct btd_device *dev, const char *uuid)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			struct btd_service *service;
			struct btd_profile *p;
			GSList *l;

			if (uuid) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
				service = find_connectable_service(dev, uuid);
				if (service)
					return g_slist_prepend(dev->pending, service);

				return dev->pending;
			}

			for (l = dev->services; l != NULL; l = g_slist_next(l)) {
				service = l->data;
				p = btd_service_get_profile(service);

				printf("jokerb %s:in %d. profile %s\n",__func__,__LINE__, p->name);
				//jokerb create_pending_list:in 1789. profile avrcp-controller
				//jokerb create_pending_list:in 1789. profile a2dp-sink
				//jokerb create_pending_list:in 1789. profile hfp
				if (!p->auto_connect) {
					//profile avrcp-controller, this profile goto here
					continue;
				}

				if (g_slist_find(dev->pending, service))
					continue;

				if (btd_service_get_state(service) !=
								BTD_SERVICE_STATE_DISCONNECTED)
					continue;

				dev->pending = g_slist_insert_sorted(dev->pending, service,
									service_prio_cmp); <tag79>
			}

			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			return dev->pending;
		}

		err = connect_next(dev);
		if (err < 0) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			if (err == -EALREADY)
				return dbus_message_new_method_return(msg);
			return btd_error_failed(msg, strerror(-err));
		}
		static int connect_next(struct btd_device *dev)
		{
			struct btd_service *service;
			int err = -ENOENT;

			while (dev->pending) {
				service = dev->pending->data;

				err = btd_service_connect(service);
				if (!err)
					return 0;
				int btd_service_connect(struct btd_service *service)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct btd_profile *profile = service->profile;
					char addr[18];
					int err;

					printf("jokerb %s:in %d.name %s\n",__func__,__LINE__, profile->name);
					if (!profile->connect) {
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
						return -ENOTSUP;
					}

					switch (service->state) {
					case BTD_SERVICE_STATE_UNAVAILABLE:
						return -EINVAL;
					case BTD_SERVICE_STATE_DISCONNECTED: //GM: into here
						break;
					case BTD_SERVICE_STATE_CONNECTING:
						return 0;
					case BTD_SERVICE_STATE_CONNECTED:
						return -EALREADY;
					case BTD_SERVICE_STATE_DISCONNECTING:
						return -EBUSY;
					}

					err = profile->connect(service);
					//hfp_connect
					//a2dp_sink_connect
					if (err == 0) {
						printf("jokerb %s:in %d.\n",__func__,__LINE__); //
						change_state(service, BTD_SERVICE_STATE_CONNECTING, 0); <tag80>
						return 0;
						static void change_state(struct btd_service *service, btd_service_state_t state,
															int err)
						{
							printf("jokerb %s:in %d.\n",__func__,__LINE__);
							btd_service_state_t old = service->state;
							char addr[18];
							GSList *l;

							if (state == old)
								return;

							btd_assert(service->device != NULL);
							btd_assert(service->profile != NULL);

							service->state = state;
							service->err = err;

							ba2str(device_get_address(service->device), addr);
							DBG("%p: device %s profile %s state changed: %s -> %s (%d)", service,
											addr, service->profile->name,
											state2str(old), state2str(state), err);
							//device 04:57:91:CC:BB:0E profile hfp state changed: disconnected -> connecting (0)

							for (l = state_callbacks; l != NULL; l = g_slist_next(l)) {
								struct service_state_callback *cb = l->data;

								cb->cb(service, old, state, cb->user_data);
								service_state_changed
								service_cb
								static void service_state_changed(struct btd_service *service,
														btd_service_state_t old_state,
														btd_service_state_t new_state,
														void *user_data)
								{
									printf("jokerb %s:in %d.\n",__func__,__LINE__);
									struct btd_profile *profile = btd_service_get_profile(service);
									struct btd_profile *btd_service_get_profile(const struct btd_service *service)
									{
										printf("jokerb %s:in %d.\n",__func__,__LINE__);
										return service->profile;
									}
									struct btd_device *device = btd_service_get_device(service);
									struct btd_device *btd_service_get_device(const struct btd_service *service)
									{
										printf("jokerb %s:in %d.\n",__func__,__LINE__);
										return service->device;
									}
									int err = btd_service_get_error(service);
									int btd_service_get_error(const struct btd_service *service)
									{
										printf("jokerb %s:in %d.\n",__func__,__LINE__);
										return service->err;
									}

									if (new_state == BTD_SERVICE_STATE_CONNECTING ||
												new_state == BTD_SERVICE_STATE_DISCONNECTING)
										return; //

									if (old_state == BTD_SERVICE_STATE_CONNECTING)
										device_profile_connected(device, profile, err);
									else if (old_state == BTD_SERVICE_STATE_DISCONNECTING)
										device_profile_disconnected(device, profile, err);
								}
								service_cb
								static void service_cb(struct btd_service *service,
														btd_service_state_t old_state,
														btd_service_state_t new_state,
														void *user_data)
								{
									printf("jokerb %s:in %d.\n",__func__,__LINE__);
									struct btd_profile *profile = btd_service_get_profile(service);
									struct reconnect_data *reconnect;

									if (g_str_equal(profile->remote_uuid, A2DP_SINK_UUID))
										sink_cb(service, old_state, new_state);
									else if (g_str_equal(profile->remote_uuid, A2DP_SOURCE_UUID))
										source_cb(service, old_state, new_state);
									else if (g_str_equal(profile->remote_uuid, AVRCP_REMOTE_UUID))
										controller_cb(service, old_state, new_state);
									else if (g_str_equal(profile->remote_uuid, AVRCP_TARGET_UUID))
										target_cb(service, old_state, new_state);

									/*
									 * Return if the reconnection feature is not enabled (all
									 * subsequent code in this function is about that).
									 */
									if (!reconnect_uuids || !reconnect_uuids[0])
										return;

									/*
									 * We're only interested in reconnecting profiles which have set
									 * auto_connect to true.
									 */
									if (!profile->auto_connect)
										return; // ?

									/*
									 * If the service went away remove it from the reconnection
									 * tracking. The function will remove the entire tracking data
									 * if this was the last service for the device.
									 */
									if (new_state == BTD_SERVICE_STATE_UNAVAILABLE) {
										reconnect_remove(service);
										return;
									}

									if (new_state != BTD_SERVICE_STATE_CONNECTED)
										return;

									/*
									 * Add an entry to track reconnections. The function will return
									 * an existing entry if there is one.
									 */
									reconnect = reconnect_add(service);

									reconnect->active = false;

									/*
									 * Should this device be reconnected? A matching UUID might not
									 * be the first profile that's connected so we might have an
									 * entry but with the reconnect flag set to false.
									 */
									if (!reconnect->reconnect)
										reconnect->reconnect = reconnect_match(profile->remote_uuid);

									DBG("Added %s reconnect %u", profile->name, reconnect->reconnect);
								}
							}
						}
					}

					ba2str(device_get_address(service->device), addr);
					error("%s profile connect failed for %s: %s", profile->name, addr,
												strerror(-err));

					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					return err;
				}

				dev->pending = g_slist_delete_link(dev->pending, dev->pending);
			}

			return err;
		}

		dev->connect = dbus_message_ref(msg);
		
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
		// return NULL;
		return dbus_message_new_method_return(msg);  // May be bluez's bug.

	resolve_services:
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		DBG("Resolving services for %s", dev->path);

		if (bdaddr_type == BDADDR_BREDR)
			err = device_browse_sdp(dev, msg);
		else {
			DBG("");
			err = device_browse_gatt(dev, msg);
		}
		if (err < 0)
			return btd_error_failed(msg, strerror(-err));

		return NULL;
	}
}

static int hfp_connect(struct btd_service *service)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct headset *hs = btd_service_get_user_data(service); <tag95>
	void *btd_service_get_user_data(const struct btd_service *service)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		return service->user_data;
	}
	DBG("%s_%d\n",__FUNCTION__,__LINE__);
	int err;
	if (hs->state == HEADSET_STATE_CONNECTING)
	{
		//return btd_error_in_progress(msg);
		DBG("%s_%d:btd_error_in_progress\n",__FUNCTION__,__LINE__);
		return -1;  // error
	}
	else if (hs->state > HEADSET_STATE_CONNECTING)
	{
		//return btd_error_already_connected(msg);
		DBG("%s_%d:btd_error_already_connected\n",__FUNCTION__,__LINE__);
		return -1;  // error
	}
	if (hs->hfp_handle && !ag.telephony_ready)
	{
		//return btd_error_not_ready(msg);
		DBG("hfp_handle=%d, ag.telephony_ready=%d\n",hs->hfp_handle,ag.telephony_ready);
		DBG("%s_%d:btd_error_not_ready\n",__FUNCTION__,__LINE__);
		return -1;  // error
	}
	hs->auto_connect = FALSE;  // may be change

	err = rfcomm_connect(hs, NULL, NULL, NULL);
	int rfcomm_connect(struct headset *hs, headset_stream_cb_t cb,
					void *user_data, unsigned int *cb_id)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		char address[18];
		GError *err = NULL;
	//  david change 080305
		DBG("%d\n",__LINE__);
		if (!manager_allow_headset_connection(hs)) {
			DBG("manager refused\n");
			return -ECONNREFUSED;
		}
		gboolean manager_allow_headset_connection(struct headset *headset_device)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			GSList *l;
			int connected = 0;
			DBG(" ");
			for (l = headsets; l != NULL; l = l->next)
			{
				struct headset *hs = l->data;

				if (hs == headset_device)
					continue;

				if (bacmp(&hs->src, &headset_device->src))
					continue;

				if (!hs)
					continue;

				if (headset_get_state(hs) > HEADSET_STATE_DISCONNECTED)
					connected++;

				if (connected >= max_connected_headsets)
					return FALSE;
			}

			return TRUE;
		}
		if (hs->rfcomm_ch < 0) { //
			return get_records(hs, cb, user_data, cb_id);
		}
		static int get_records(struct headset *hs, headset_stream_cb_t cb,
					 void *user_data, unsigned int *cb_id)
		{
			 uint16_t svclass;
			 uuid_t uuid;
			 int err;
			 DBG("%d\n",__LINE__);
			 if (hs->pending && hs->pending->svclass == HANDSFREE_SVCLASS_ID)
				 svclass = HEADSET_SVCLASS_ID;
			 else
				 svclass = hs->search_hfp ? HANDSFREE_SVCLASS_ID :
									 HEADSET_SVCLASS_ID;

			 //sdp_uuid16_create(&uuid, svclass);
			 DBG("%s_%d, svclass =	%x\n",__FUNCTION__,__LINE__, svclass);
			 //get_records_1723, svclass = 111e
			 sdp_uuid16_create(&uuid, HANDSFREE_SVCLASS_ID);

			 struct btd_adapter *adapter = device_get_adapter(hs->btd_dev);
			 err = bt_search_service(btd_adapter_get_address(adapter),
										device_get_address(hs->btd_dev),
										&uuid,
										get_record_cb,
										hs, NULL, 0);
			 if (err < 0)
				 return err;
			 if (hs->pending) {
				 hs->pending->svclass = svclass;
				 return 0;
			 }
			 headset_set_state(hs, HEADSET_STATE_CONNECTING); <tag96>
			void headset_set_state(struct headset *hs, headset_state_t state)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct headset_slc *slc = hs->slc;
				gboolean value;
				const char *state_str;
				headset_state_t old_state = hs->state;
				GSList *l;

				if (old_state == state)
					return;
				state_str = state2str(state);

				struct dev_priv *priv = hs->priv;
				DBusMessage *reply = NULL;

				switch (state) {
				case HEADSET_STATE_CONNECTING:
					priv->dc_id = device_add_disconnect_watch(hs->btd_dev,headset_disconnect_cb, hs, NULL);
					g_dbus_emit_property_changed(hs->conn, hs->path,AUDIO_HEADSET_INTERFACE, "State");
					break;
				}

				hs->state = state;

				DBG("State changed %s: %s -> %s", hs->path, str_state[old_state],
					str_state[state]);
				//State changed /org/bluez/hci0/dev_04_57_91_CC_BB_0E:
				//HEADSET_STATE_DISCONNECTED -> HEADSET_STATE_CONNECTING

				for (l = headset_callbacks; l != NULL; l = l->next) {
					struct headset_state_callback *cb = l->data;
					cb->cb(hs, old_state, state, cb->user_data);
				}
				device_headset_cb
				static void device_headset_cb(struct headset *hs,
								headset_state_t old_state,
								headset_state_t new_state,
								void *user_data)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					if (!hs)
						return;
					struct dev_priv *priv = hs->priv;
					priv->hs_state = new_state;

					switch (new_state) {
					case HEADSET_STATE_CONNECTING:
						DBG("HEADSET_STATE_CONNECTING\n");
						device_remove_headset_timer(hs);
						static void device_remove_headset_timer(struct headset *hs)
						{
							printf("jokerb %s:in %d.\n",__func__,__LINE__);
							if (hs->priv->headset_timer)
								g_source_remove(hs->priv->headset_timer);
							hs->priv->headset_timer = 0;
						}
						break;
					}
				}
			}

			 DBG("set hs connected\n");
			 pending_connect_init(hs, HEADSET_STATE_CONNECTED);
			static void pending_connect_init(struct headset *hs, headset_state_t target_state)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				if (hs->pending) {
					if (hs->pending->target_state < target_state)
						hs->pending->target_state = target_state;
					return;
				}

				hs->pending = g_new0(struct pending_connect, 1);
				hs->pending->target_state = target_state;
			}

			 hs->pending->svclass = svclass;

			 if (cb) {
				 DBG("%d\n",__LINE__);
				 unsigned int id;
				 id = connect_cb_new(hs, HEADSET_STATE_CONNECTED,
							 cb, user_data);
				 if (cb_id)
					 *cb_id = id;
			 }
			 return 0;
		 }

		ba2str(&hs->dst, address);

		DBG("%s: Connecting to %s channel %d", hs->path, address,hs->rfcomm_ch);
		///org/bluez/hci0/dev_04_57_91_CC_BB_0E: Connecting to 04:57:91:CC:BB:0E channel 4

		hs->tmp_rfcomm = bt_io_connect(headset_connect_cb, hs,
						NULL, &err,
						BT_IO_OPT_SOURCE_BDADDR, &hs->src,
						BT_IO_OPT_DEST_BDADDR, &hs->dst,
						BT_IO_OPT_CHANNEL, hs->rfcomm_ch,
						BT_IO_OPT_INVALID);

		hs->rfcomm_ch = -1;

		if (!hs->tmp_rfcomm) {
			DBG("hs->tmp_rfcomm is null\n");
			error("%s", err->message);
			g_error_free(err);
			return -EIO;
		}

		hs->hfp_active = hs->hfp_handle != 0 ? TRUE : FALSE;

		headset_set_state(hs, HEADSET_STATE_CONNECTING);

		DBG("set hs connected\n");
		pending_connect_init(hs, HEADSET_STATE_CONNECTED);

		if (cb) { //GM : no into
			DBG("%d\n",__LINE__);
			unsigned int id = connect_cb_new(hs, HEADSET_STATE_CONNECTED,
								cb, user_data);
			if (cb_id)
				*cb_id = id;
		}
		return 0;
	}

	if (err < 0)
	{
		//return btd_error_failed(msg, strerror(-err));
		DBG("%s_%d, err = %d\n",__FUNCTION__,__LINE__, err);
		return -1;  // error
	}
	hs->auto_dc = FALSE;
	//btd_service_connecting_complete(service, 0);
	return 0;
}

static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct headset *hs = user_data;
	struct pending_connect *p = hs->pending;
	sdp_record_t *record = NULL;
	sdp_list_t *r;
	uuid_t uuid;
	DBG("%d\n",__LINE__);
	assert(hs->pending != NULL);

	if (err < 0) {
		error("Unable to get service record: %s (%d)",
							strerror(-err), -err);
		p->err = -err;
		if (p->msg)
			error_connect_failed(hs->conn, p->msg, p->err);
		goto failed;
	}

	if (!recs || !recs->data) {
		error("No records found");
		goto failed_not_supported;
	}

	sdp_uuid16_create(&uuid, p->svclass);

	for (r = recs; r != NULL; r = r->next) {
		sdp_list_t *classes;
		uuid_t class;

		record = r->data;

		if (sdp_get_service_classes(record, &classes) < 0) {
			error("Unable to get service classes from record");
			continue;
		}

		memcpy(&class, classes->data, sizeof(uuid));

		sdp_list_free(classes, free);


		if (sdp_uuid_cmp(&class, &uuid) == 0)
			break;
	}

	if (r == NULL) {
		error("No record found with UUID 0x%04x", p->svclass);
		goto failed_not_supported;
	}

	if (headset_set_channel(hs, record, p->svclass) < 0) {
		error("Unable to extract RFCOMM channel from service record");
		goto failed_not_supported;
	}
	static int headset_set_channel(struct headset *headset,
					const sdp_record_t *record, uint16_t svc)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		int ch;
		sdp_list_t *protos;

		if (sdp_get_access_protos(record, &protos) < 0) {
			error("Unable to get access protos from headset record");
			return -1;
		}

		ch = sdp_get_proto_port(protos, RFCOMM_UUID);

		sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
		sdp_list_free(protos, NULL);

		if (ch <= 0) {
			error("Unable to get RFCOMM channel from Headset record");
			return -1;
		}

		headset->rfcomm_ch = ch;

		if (svc == HANDSFREE_SVCLASS_ID) {
			headset->hfp_handle = record->handle;
			DBG("Discovered Handsfree service on channel %d", ch);
		} else {
			headset->hsp_handle = record->handle;
			DBG("Discovered Headset service on channel %d", ch);
			 //Discovered Handsfree service on channel 4
		}

		return 0;
	}

	/* Set svclass to 0 so we can easily check that SDP is no-longer
	 * going on (to know if bt_cancel_discovery needs to be called) */
	p->svclass = 0;
	err = rfcomm_connect(hs, NULL, NULL, NULL);
	if (err < 0) {
		error("Unable to connect: %s (%d)", strerror(-err), -err);
		p->err = -err;
		error_connect_failed(hs->conn, p->msg, p->err);  // david : this loop
		goto failed;
	}
	int rfcomm_connect(struct headset *hs, headset_stream_cb_t cb,
					void *user_data, unsigned int *cb_id)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		char address[18];
		GError *err = NULL;
	//  david change 080305
		DBG("%d\n",__LINE__);
		if (!manager_allow_headset_connection(hs)) {
			DBG("manager refused\n");
			return -ECONNREFUSED;
		}
		gboolean manager_allow_headset_connection(struct headset *headset_device)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			GSList *l;
			int connected = 0;
			DBG(" ");
			for (l = headsets; l != NULL; l = l->next)
			{
				struct headset *hs = l->data;

				if (hs == headset_device)
					continue;

				if (bacmp(&hs->src, &headset_device->src))
					continue;

				if (!hs)
					continue;

				if (headset_get_state(hs) > HEADSET_STATE_DISCONNECTED)
					connected++;

				if (connected >= max_connected_headsets)
					return FALSE;
			}

			return TRUE;
		}
		if (hs->rfcomm_ch < 0)
			return get_records(hs, cb, user_data, cb_id);

		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		ba2str(&hs->dst, address);

		DBG("%s: Connecting to %s channel %d", hs->path, address,hs->rfcomm_ch);
		///org/bluez/hci0/dev_04_57_91_CC_BB_0E: Connecting to 04:57:91:CC:BB:0E channel 4

		hs->tmp_rfcomm = bt_io_connect(headset_connect_cb, hs,
						NULL, &err,
						BT_IO_OPT_SOURCE_BDADDR, &hs->src,
						BT_IO_OPT_DEST_BDADDR, &hs->dst,
						BT_IO_OPT_CHANNEL, hs->rfcomm_ch,
						BT_IO_OPT_INVALID);

		hs->rfcomm_ch = -1;

		if (!hs->tmp_rfcomm) {
			DBG("hs->tmp_rfcomm is null\n");
			error("%s", err->message);
			g_error_free(err);
			return -EIO;
		}

		hs->hfp_active = hs->hfp_handle != 0 ? TRUE : FALSE;

		headset_set_state(hs, HEADSET_STATE_CONNECTING);

		DBG("set hs connected\n");
		pending_connect_init(hs, HEADSET_STATE_CONNECTED);

		if (cb) {
			DBG("%d\n",__LINE__);
			unsigned int id = connect_cb_new(hs, HEADSET_STATE_CONNECTED,
								cb, user_data);
			if (cb_id)
				*cb_id = id;
		}
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
		return 0;
	}

	return;

failed_not_supported:
	if (p->svclass == HANDSFREE_SVCLASS_ID &&
			get_records(hs, NULL, NULL, NULL) == 0)
		return;
	if (p->msg) {
		DBusMessage *reply = btd_error_not_supported(p->msg);
		g_dbus_send_message(hs->conn, reply);
	}
failed:
	p->svclass = 0;
	pending_connect_finalize(hs);
	btd_service_connecting_complete(hs->service, err);  // david
	headset_set_state(hs, HEADSET_STATE_DISCONNECTED);
}

// btio/btio.c
static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
							gpointer user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct connect *conn = user_data;
	GError *gerr = NULL;
	int err, sk_err, sock;
	socklen_t len = sizeof(sk_err);

	/* If the user aborted this connect attempt */
	if ((cond & G_IO_NVAL) || check_nval(io))
		return FALSE;

	sock = g_io_channel_unix_get_fd(io);

	if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
		err = -errno;
	else
		err = -sk_err;

	if (err < 0)
		ERROR_FAILED(&gerr, "connect error", -err);

	conn->connect(io, gerr, conn->user_data);
	headset_connect_cb

	g_clear_error(&gerr);

	return FALSE;
}

headset_connect_cb
static void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct headset *hs = user_data;
	struct pending_connect *p = hs->pending;
	char hs_address[18];

    DBG("");
	if (err) {
		error("%s", err->message);
		goto failed;
	}

	/* For HFP telephony isn't ready just disconnect */
	if (hs->hfp_active && !ag.telephony_ready) {
		error("Unable to accept HFP connection since the telephony "
				"subsystem isn't initialized");
		goto failed;
	}

	hs->rfcomm = hs->tmp_rfcomm;
	hs->tmp_rfcomm = NULL;

	ba2str(&hs->dst, hs_address);

	if (p)
		p->io = NULL;
	else
		hs->auto_dc = FALSE;

	g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,
			(GIOFunc) rfcomm_io_cb, hs);

	DBG("%s: Connected to %s", hs->path, hs_address);
	// /org/bluez/hci0/dev_04_57_91_CC_BB_0E: Connected to 04:57:91:CC:BB:0E

	hs->slc = g_new0(struct headset_slc, 1);
	hs->slc->sp_gain = 15;
	hs->slc->mic_gain = 15;
	hs->slc->nrec = TRUE;

	/* In HFP mode wait for Service Level Connection */
	if (hs->hfp_active) { //
        DBG("return\n");
		return;
    }

	headset_set_state(hs, HEADSET_STATE_CONNECTED);

	if (p && p->target_state == HEADSET_STATE_PLAYING) {
        DBG("call sco connect\n");
		p->err = sco_connect(hs, NULL, NULL, NULL);
		if (p->err < 0)
			goto failed;
		return;
	}

	if (p && p->msg) {
		DBusMessage *reply = dbus_message_new_method_return(p->msg);
		g_dbus_send_message(hs->conn, reply);
	}

	pending_connect_finalize(hs);

    DBG("return\n");
	return;

failed:
	if (p && p->msg)
		error_connect_failed(hs->conn, p->msg, p->err);
	pending_connect_finalize(hs);
	if (hs->rfcomm) {
        DBG("set hs connected\n");
		headset_set_state(hs, HEADSET_STATE_CONNECTED);
    }
	else {
        DBG("set hs disconnected\n");
		headset_set_state(hs, HEADSET_STATE_DISCONNECTED);
    }
    DBG("return\n");
}

//蓝牙耳机按下PPT键或其他按钮时:
static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
				struct headset *hs)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct headset_slc *slc;
	unsigned char buf[BUF_SIZE];
	ssize_t bytes_read;
	size_t free_space;
	int fd;

	if (cond & G_IO_NVAL) {
        DBG("return false\n");
		return FALSE;
    }

	slc = hs->slc;

	if (cond & (G_IO_ERR | G_IO_HUP)) {
		DBG("ERR or HUP on RFCOMM socket");
		goto failed;
	}

	fd = g_io_channel_unix_get_fd(chan);

	bytes_read = read(fd, buf, sizeof(buf) - 1);
	if (bytes_read < 0)
		return TRUE;

    //DBG("%s:buf:%s\n",__FUNCTION__,buf);

	free_space = sizeof(slc->buf) - slc->data_start -
			slc->data_length - 1;

	if (free_space < (size_t) bytes_read) {
		/* Very likely that the HS is sending us garbage so
		 * just ignore the data and disconnect */
		error("Too much data to fit incomming buffer");
		goto failed;
	}

	memcpy(&slc->buf[slc->data_start], buf, bytes_read);
	slc->data_length += bytes_read;

	/* Make sure the data is null terminated so we can use string
	 * functions */
	slc->buf[slc->data_start + slc->data_length] = '\0';

	while (slc->data_length > 0) {
		char *cr;
		int err;
		off_t cmd_len;

		cr = strchr(&slc->buf[slc->data_start], '\r');
		if (!cr)
			break;

		cmd_len = 1 + (off_t) cr - (off_t) &slc->buf[slc->data_start];
		*cr = '\0';

		if (cmd_len > 1)
			err = handle_event(hs, &slc->buf[slc->data_start]);
		else
			/* Silently skip empty commands */
			err = 0;
		static int handle_event(struct headset *hs, const char *buf)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			struct event *ev;

			DBG("Received %s", buf);
			//Received AT+PTT 1
			//Received AT+PTT 0
			//Received AT+BRSF=159

			for (ev = event_callbacks; ev->cmd; ev++) {
				if (!strncmp(buf, ev->cmd, strlen(ev->cmd)))
					return ev->callback(hs, buf);
					//ptt_signal
					//supported_features
			}
			static int ptt_signal(struct headset *hs, const char *buf)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
					//DBG("%s:%s",__FUNCTION__,buf);
					if (strlen(buf) < 8)
							return -EINVAL;

					/*hard coding. not so good but follow originals*/
					if( buf[7] == '1' )
					{
							g_dbus_emit_signal(hs->conn, hs->path,
									AUDIO_HEADSET_INTERFACE, "PTTKeyPressed",
									DBUS_TYPE_INVALID);
					}
					else
					{
							g_dbus_emit_signal(hs->conn, hs->path,
									AUDIO_HEADSET_INTERFACE, "PTTKeyReleased",
									DBUS_TYPE_INVALID);
					}

					return headset_send(hs, "\r\nOK\r\n");
					static int headset_send(struct headset *hs, char *format, ...)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						va_list ap;
						int ret;

						va_start(ap, format);
						ret = headset_send_valist(hs, format, ap);
						static int headset_send_valist(struct headset *hs, char *format, va_list ap)
						{
							printf("jokerb %s:in %d.\n",__func__,__LINE__);
							char rsp[BUF_SIZE];
							ssize_t total_written, count;
							int fd;

							count = vsnprintf(rsp, sizeof(rsp), format, ap);

							if (count < 0)
								return -EINVAL;

							if (!hs->rfcomm) {
								//error("headset_send: the headset is not connected");
								DBG("headset_send: the headset is not connected");
								return -EIO;
							}

							total_written = 0;
							fd = g_io_channel_unix_get_fd(hs->rfcomm);

							while (total_written < count) {
								ssize_t written;

								written = write(fd, rsp + total_written,
										count - total_written);
								if (written < 0)
									return -errno;

								total_written += written;
							}

							return 0;
						}
						va_end(ap);

						return ret;
					}
			}
			supported_features
			static int supported_features(struct headset *hs, const char *buf)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct headset_slc *slc = hs->slc;
				int err;

				if (strlen(buf) < 9)
					return -EINVAL;

				DBG("");
				slc->hf_features = strtoul(&buf[8], NULL, 10);

				print_hf_features(slc->hf_features);

				err = headset_send(hs, "\r\n+BRSF: %u\r\n", ag.features);
				if (err < 0)
					return err;

				return headset_send(hs, "\r\nOK\r\n");
			}

			return -EINVAL;
		}

		if (err == -EINVAL) {
			info("Badly formated or unrecognized command: %s",
					&slc->buf[slc->data_start]);
			err = headset_send(hs, "\r\nERROR\r\n");
		} else if (err < 0)
			error("Error handling command %s: %s (%d)",
						&slc->buf[slc->data_start],
						strerror(-err), -err);

		slc->data_start += cmd_len;
		slc->data_length -= cmd_len;

		if (!slc->data_length)
			slc->data_start = 0;
	}

	return TRUE;

failed:
    DBG("set disconnected\n");
	headset_set_state(hs, HEADSET_STATE_DISCONNECTED);

	return FALSE;
}

// AT+ callback
// AT+CMER=3,0,0,1
static int event_reporting(struct headset *hs, const char *buf)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	char **tokens; /* <mode>, <keyp>, <disp>, <ind>, <bfr> */

	if (strlen(buf) < 13)
		return -EINVAL;

	tokens = g_strsplit(&buf[8], ",", 5);
	if (g_strv_length(tokens) < 4) {
		g_strfreev(tokens);
		return -EINVAL;
	}

	ag.er_mode = atoi(tokens[0]);
	ag.er_ind = atoi(tokens[3]);

	g_strfreev(tokens);
	tokens = NULL;

	DBG("Event reporting (CMER): mode=%d, ind=%d",
			ag.er_mode, ag.er_ind);
	//Event reporting (CMER): mode=3, ind=1

	switch (ag.er_ind) {
	case 0:
	case 1: //
		telephony_event_reporting_req(hs, ag.er_ind);
		void telephony_event_reporting_req(void *telephony_device, int ind)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			events_enabled = ind == 1 ? TRUE : FALSE;

			telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
			int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct headset *hs = telephony_device;
				struct headset_slc *slc = hs->slc;
				int ret;

				if (err != CME_ERROR_NONE) {
					return telephony_generic_rsp(telephony_device, err);
				}

				ret = headset_send(hs, "\r\nOK\r\n");
				if (ret < 0)
					return ret;

				if (hs->state != HEADSET_STATE_CONNECTING)
					return 0;

				if (slc->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY &&
						ag.features & AG_FEATURE_THREE_WAY_CALLING)
					return 0;

				hfp_slc_complete(hs); //
				static void hfp_slc_complete(struct headset *hs)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct pending_connect *p = hs->pending;

					DBG("HFP Service Level Connection established");

					headset_set_state(hs, HEADSET_STATE_CONNECTED); <tag97>
					void headset_set_state(struct headset *hs, headset_state_t state)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						struct headset_slc *slc = hs->slc;
						gboolean value;
						const char *state_str;
						headset_state_t old_state = hs->state;
						GSList *l;

						if (old_state == state)
							return;
						state_str = state2str(state);

						struct dev_priv *priv = hs->priv;
						DBusMessage *reply = NULL;

						switch (state) {
						case HEADSET_STATE_CONNECTED:
							// david add
							if (priv->conn_req)
							{
								reply = dbus_message_new_method_return(priv->conn_req);
								dbus_message_unref(priv->conn_req);
								priv->conn_req = NULL;
								g_dbus_send_message(hs->conn, reply);
							}

							close_sco(hs);
							static void close_sco(struct headset *hs)
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								if (hs->sco) {
									int sock = g_io_channel_unix_get_fd(hs->sco);
									DBG("shutdown\n");
									shutdown(sock, SHUT_RDWR);
									g_io_channel_shutdown(hs->sco, TRUE, NULL);
									g_io_channel_unref(hs->sco);
									hs->sco = NULL;
								}

								if (hs->sco_id) {
									g_source_remove(hs->sco_id);
									hs->sco_id = 0;
								}
							}
							if (hs->state != HEADSET_STATE_PLAY_IN_PROGRESS)
								g_dbus_emit_property_changed(hs->conn, hs->path,AUDIO_HEADSET_INTERFACE, "State");
							if (hs->state < state) { //
								if (ag.features & AG_FEATURE_INBAND_RINGTONE)
									slc->inband_ring = TRUE;
								else
									slc->inband_ring = FALSE;
								g_dbus_emit_signal(hs->conn, hs->path,
											AUDIO_HEADSET_INTERFACE,
											"Connected",
											DBUS_TYPE_INVALID);
								value = TRUE;

								g_dbus_emit_property_changed(hs->conn, hs->path,AUDIO_HEADSET_INTERFACE, "Connected");

								active_devices = g_slist_append(active_devices, hs);
								telephony_device_connected(hs);
								void telephony_device_connected(void *telephony_device)
								{
									printf("jokerb %s:in %d.\n",__func__,__LINE__);
									DBG("telephony-dummy: device %p connected", telephony_device);
									//telephony-dummy: device 0x112a80 connected
								}
							} else if (hs->state == HEADSET_STATE_PLAYING) {
								value = FALSE;
								g_dbus_emit_signal(hs->conn, hs->path,
											AUDIO_HEADSET_INTERFACE,
											"Stopped",
											DBUS_TYPE_INVALID);

								g_dbus_emit_property_changed(hs->conn, hs->path,AUDIO_HEADSET_INTERFACE, "Playing");

							} else if(hs->state == HEADSET_STATE_PLAY_IN_PROGRESS) {
								terminate_call(hs,NULL);
							}

							btd_service_connecting_complete(hs->service, 0); //
							void btd_service_connecting_complete(struct btd_service *service, int err)
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								if (service->state != BTD_SERVICE_STATE_DISCONNECTED &&
										service->state != BTD_SERVICE_STATE_CONNECTING)
									return;

								if (err == 0) {
									change_state(service, BTD_SERVICE_STATE_CONNECTED, 0); <tag94>
									static void change_state(struct btd_service *service, btd_service_state_t state,
																		int err)
									{
										printf("jokerb %s:in %d.\n",__func__,__LINE__);
										btd_service_state_t old = service->state;
										char addr[18];
										GSList *l;

										if (state == old)
											return;

										btd_assert(service->device != NULL);
										btd_assert(service->profile != NULL);

										service->state = state;
										service->err = err;

										ba2str(device_get_address(service->device), addr);
										DBG("%p: device %s profile %s state changed: %s -> %s (%d)", service,
														addr, service->profile->name,
														state2str(old), state2str(state), err);
										//device 04:57:91:CC:BB:0E profile hfp state changed: connecting -> connected (0)

										for (l = state_callbacks; l != NULL; l = g_slist_next(l)) {
											struct service_state_callback *cb = l->data;

											cb->cb(service, old, state, cb->user_data);
											service_state_changed
											static void service_state_changed(struct btd_service *service,
																	btd_service_state_t old_state,
																	btd_service_state_t new_state,
																	void *user_data)
											{
												printf("jokerb %s:in %d.\n",__func__,__LINE__);
												struct btd_profile *profile = btd_service_get_profile(service);
												struct btd_device *device = btd_service_get_device(service);
												int err = btd_service_get_error(service);

												if (new_state == BTD_SERVICE_STATE_CONNECTING ||
															new_state == BTD_SERVICE_STATE_DISCONNECTING)
													return;

												if (old_state == BTD_SERVICE_STATE_CONNECTING) {
													device_profile_connected(device, profile, err);
													static void device_profile_connected(struct btd_device *dev,
																		struct btd_profile *profile, int err)
													{
														printf("jokerb %s:in %d.\n",__func__,__LINE__);
														struct btd_service *pending;
														GSList *l;

														DBG("%s %s (%d)", profile->name, strerror(-err), -err);
														//hfp Success (0)

														if (!err)
															btd_device_set_temporary(dev, false); //

														if (dev->pending == NULL)
															goto done;

														if (!btd_device_is_connected(dev)) {
															switch (-err) {
															case EHOSTDOWN: /* page timeout */
															case EHOSTUNREACH: /* adapter not powered */
															case ECONNABORTED: /* adapter powered down */
																goto done;
															}
														}


														pending = dev->pending->data;
														l = find_service_with_profile(dev->pending, profile);
														static GSList *find_service_with_profile(GSList *list,
																					struct btd_profile *p)
														{
															printf("jokerb %s:in %d.\n",__func__,__LINE__);
															GSList *l;

															for (l = list; l != NULL; l = g_slist_next(l)) {
																struct btd_service *service = l->data;

																if (btd_service_get_profile(service) == p)
																	return l;
															}

															return NULL;
														}
														if (l != NULL)
															dev->pending = g_slist_delete_link(dev->pending, l);

														/* Only continue connecting the next profile if it matches the first
														 * pending, otherwise it will trigger another connect to the same
														 * profile
														 */
														if (profile != btd_service_get_profile(pending))
															return;

														if (connect_next(dev) == 0)
															return;
														static int connect_next(struct btd_device *dev)
														{
															printf("jokerb %s:in %d.\n",__func__,__LINE__);
															struct btd_service *service;
															int err = -ENOENT;

															while (dev->pending) {
																service = dev->pending->data;

																err = btd_service_connect(service);
																if (!err)
																	return 0;

																dev->pending = g_slist_delete_link(dev->pending,
																							dev->pending);
															}

															return err;
														}

													done:
														g_slist_free(dev->pending);
														dev->pending = NULL;

														if (!dev->connect)
															return;

														if (!err && dbus_message_is_method_call(dev->connect,
																					DEVICE_INTERFACE,
																					"Connect"))
															dev->general_connect = TRUE;

														DBG("returning response to %s",
																	dbus_message_get_sender(dev->connect));
														//returning response to :1.1

														l = find_service_with_state(dev->services,
																	BTD_SERVICE_STATE_CONNECTED);
														static GSList *find_service_with_state(GSList *list,
																				btd_service_state_t state)
														{
															printf("jokerb %s:in %d.\n",__func__,__LINE__);
															GSList *l;

															for (l = list; l != NULL; l = g_slist_next(l)) {
																struct btd_service *service = l->data;

																if (btd_service_get_state(service) == state)
																	return l;
																btd_service_state_t btd_service_get_state(
																			const struct btd_service *service)
																{
																	printf("jokerb %s:in %d.\n",__func__,__LINE__);
																	return service->state;
																}
															}

															return NULL;
														}

														if (err && l == NULL) {
														printf("jokerb %s:in %d.\n",__func__,__LINE__);
															/* Fallback to LE bearer if supported */
															if (err == -EHOSTDOWN && dev->le &&
																		!dev->le_state.connected)
															{
																printf("jokerb %s:in %d.\n",__func__,__LINE__);
																err = device_connect_le(dev);
																if (err == 0) {
																	printf("jokerb %s:in %d.\n",__func__,__LINE__);
																	return;
																}
															}

															g_dbus_send_message(dbus_conn,
																	btd_error_failed(dev->connect, strerror(-err)));
														} else {
														printf("jokerb %s:in %d.\n",__func__,__LINE__); //
															/* Start passive SDP discovery to update known services */
															if (dev->bredr && !dev->svc_refreshed) {
														printf("jokerb %s:in %d.\n",__func__,__LINE__); //
																device_browse_sdp(dev, NULL);
															}
															g_dbus_send_reply(dbus_conn, dev->connect,
																					DBUS_TYPE_INVALID);
														}

														dbus_message_unref(dev->connect);
														dev->connect = NULL;
														printf("jokerb %s:in %d.\n",__func__,__LINE__); //
													}
												}
												else if (old_state == BTD_SERVICE_STATE_DISCONNECTING)
													device_profile_disconnected(device, profile, err);
											}
										}
									}
								}
								else
									change_state(service, BTD_SERVICE_STATE_DISCONNECTED, err);
							}
							break;
						}

						hs->state = state;

						DBG("State changed %s: %s -> %s", hs->path, str_state[old_state],
							str_state[state]);
						//State changed /org/bluez/hci0/dev_04_57_91_CC_BB_0E:
						//HEADSET_STATE_CONNECTING -> HEADSET_STATE_CONNECTED

						for (l = headset_callbacks; l != NULL; l = l->next) {
							struct headset_state_callback *cb = l->data;
							cb->cb(hs, old_state, state, cb->user_data);
							device_headset_cb
						}
					}

					if (p == NULL)
						return;

					if (p->target_state == HEADSET_STATE_CONNECTED) { //
						if (p->msg) {
							DBusMessage *reply = dbus_message_new_method_return(p->msg);
							g_dbus_send_message(hs->conn, reply);
						}
						pending_connect_finalize(hs);
						return;
						static void pending_connect_finalize(struct headset *hs)
						{
							printf("jokerb %s:in %d.\n",__func__,__LINE__);
							struct pending_connect *p = hs->pending;

							if (p == NULL)
								return;

							if (p->svclass)
								bt_cancel_discovery(&hs->src, &hs->dst);

							g_slist_foreach(p->callbacks, (GFunc) pending_connect_complete, hs);

							g_slist_foreach(p->callbacks, (GFunc) g_free, NULL);
							g_slist_free(p->callbacks);

							if (p->io) {
								DBG("shutdown");
								g_io_channel_shutdown(p->io, TRUE, NULL);
								g_io_channel_unref(p->io);
							}

							if (p->msg)
								dbus_message_unref(p->msg);

							if (p->call) {
								dbus_pending_call_cancel(p->call);
								dbus_pending_call_unref(p->call);
							}

							g_free(p);

							hs->pending = NULL;
						}
					}

					p->err = sco_connect(hs, NULL, NULL, NULL);
					if (p->err < 0) {
						if (p->msg)
							error_connect_failed(hs->conn, p->msg, p->err);
						pending_connect_finalize(hs);
					}
				}

				return 0;
			}
		}
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static void service_cb(struct btd_service *service,
						btd_service_state_t old_state,
						btd_service_state_t new_state,
						void *user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct btd_profile *profile = btd_service_get_profile(service);
	struct reconnect_data *reconnect;

	if (g_str_equal(profile->remote_uuid, A2DP_SINK_UUID))
		sink_cb(service, old_state, new_state);
	else if (g_str_equal(profile->remote_uuid, A2DP_SOURCE_UUID))
		source_cb(service, old_state, new_state);
	else if (g_str_equal(profile->remote_uuid, AVRCP_REMOTE_UUID))
		controller_cb(service, old_state, new_state);
	else if (g_str_equal(profile->remote_uuid, AVRCP_TARGET_UUID))
		target_cb(service, old_state, new_state);

	/*
	 * Return if the reconnection feature is not enabled (all
	 * subsequent code in this function is about that).
	 */
	if (!reconnect_uuids || !reconnect_uuids[0])
		return;

	/*
	 * We're only interested in reconnecting profiles which have set
	 * auto_connect to true.
	 */
	if (!profile->auto_connect)
		return;

	/*
	 * If the service went away remove it from the reconnection
	 * tracking. The function will remove the entire tracking data
	 * if this was the last service for the device.
	 */
	if (new_state == BTD_SERVICE_STATE_UNAVAILABLE) {
		reconnect_remove(service);
		return;
	}

	if (new_state != BTD_SERVICE_STATE_CONNECTED)
		return;

	/*
	 * Add an entry to track reconnections. The function will return
	 * an existing entry if there is one.
	 */
	reconnect = reconnect_add(service);
	static struct reconnect_data *reconnect_add(struct btd_service *service)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct btd_device *dev = btd_service_get_device(service);
		struct reconnect_data *reconnect;

		reconnect = reconnect_find(dev);
		if (!reconnect) {
			reconnect = g_new0(struct reconnect_data, 1);
			reconnect->dev = dev;
			reconnects = g_slist_append(reconnects, reconnect);
		}
		static struct reconnect_data *reconnect_find(struct btd_device *dev)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			GSList *l;

			for (l = reconnects; l; l = g_slist_next(l)) {
				struct reconnect_data *reconnect = l->data;

				if (reconnect->dev == dev)
					return reconnect;
			}

			return NULL;
		}

		if (g_slist_find(reconnect->services, service))
			return reconnect;

		reconnect->services = g_slist_append(reconnect->services,
							btd_service_ref(service));

		return reconnect;
	}

	reconnect->active = false;

	/*
	 * Should this device be reconnected? A matching UUID might not
	 * be the first profile that's connected so we might have an
	 * entry but with the reconnect flag set to false.
	 */
	if (!reconnect->reconnect) { //
		reconnect->reconnect = reconnect_match(profile->remote_uuid);
	}
	static bool reconnect_match(const char *uuid)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		char **str;

		if (!reconnect_uuids)
			return false;

		for (str = reconnect_uuids; *str; str++) {
			if (!bt_uuid_strcmp(uuid, *str))
				return true;
		}

		return false;
	}

	DBG("Added %s reconnect %u", profile->name, reconnect->reconnect);
	//Added hfp reconnect 0
}

// AT+CLIP=1
cli_notification
static int cli_notification(struct headset *hs, const char *buf)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct headset_slc *slc = hs->slc;

	if (strlen(buf) < 9)
		return -EINVAL;

	slc->cli_active = buf[8] == '1' ? TRUE : FALSE;

	return headset_send(hs, "\r\nOK\r\n");
}

################## 蓝牙设备自动连接 host 的情况 ########
static void connected_callback(uint16_t index, uint16_t length,
					const void *param, void *user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	const struct mgmt_ev_device_connected *ev = param;
	struct btd_adapter *adapter = user_data;
	struct btd_device *device;
	struct eir_data eir_data;
	uint16_t eir_len;
	char addr[18];
	bool name_known;

	if (length < sizeof(*ev)) {
		btd_error(adapter->dev_id, "Too small device connected event");
		return;
	}

	eir_len = btohs(ev->eir_len);
	if (length < sizeof(*ev) + eir_len) {
		btd_error(adapter->dev_id, "Too small device connected event");
		return;
	}

	ba2str(&ev->addr.bdaddr, addr);

	DBG("hci%u device %s connected eir_len %u", index, addr, eir_len);

	device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,ev->addr.type);
	if (!device) {
		btd_error(adapter->dev_id,
				"Unable to get device object for %s", addr);
		return;
	}

	memset(&eir_data, 0, sizeof(eir_data));
	if (eir_len > 0) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
		eir_parse(&eir_data, ev->eir, eir_len);
	}

	if (eir_data.class != 0) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
		device_set_class(device, eir_data.class);
	}

	adapter_add_connection(adapter, device, ev->addr.type);
	static void adapter_add_connection(struct btd_adapter *adapter,
							struct btd_device *device,
							uint8_t bdaddr_type)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		device_add_connection(device, bdaddr_type);
		void device_add_connection(struct btd_device *dev, uint8_t bdaddr_type)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			struct bearer_state *state = get_state(dev, bdaddr_type);

			device_update_last_seen(dev, bdaddr_type);

			if (state->connected) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
				char addr[18];
				ba2str(&dev->bdaddr, addr);
				error("Device %s is already connected", addr);
				return;
			}

			bacpy(&dev->conn_bdaddr, &dev->bdaddr);
			dev->conn_bdaddr_type = dev->bdaddr_type;

			/* If this is the first connection over this bearer */
			if (bdaddr_type == BDADDR_BREDR) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__); //
				device_set_bredr_support(dev); // GM in here
			}
			else {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
				device_set_le_support(dev, bdaddr_type);
			}

			state->connected = true;

			if (dev->le_state.connected && dev->bredr_state.connected) {
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
				return;
			}

			g_dbus_emit_property_changed(dbus_conn, dev->path, DEVICE_INTERFACE,"Connected");
			printf("jokerb %s:in %d.\n",__func__,__LINE__); //
		}

		if (g_slist_find(adapter->connections, device)) {
			btd_error(adapter->dev_id,
					"Device is already marked as connected");
			return;
		}

		adapter->connections = g_slist_append(adapter->connections, device);
	}

	name_known = device_name_known(device);

	if (eir_data.name && (eir_data.name_complete || !name_known)) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__); //
		device_store_cached_name(device, eir_data.name);
		btd_device_device_set_name(device, eir_data.name);
	}

	if (eir_data.msd_list) {
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		adapter_msd_notify(adapter, device, eir_data.msd_list);
	}

	eir_data_free(&eir_data);
	printf("jokerb %s:in %d.\n",__func__,__LINE__); //
}

static gboolean dev_property_get_connected(const GDBusPropertyTable *property,
					DBusMessageIter *iter, void *data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct btd_device *dev = data;
	dbus_bool_t connected;

	if (dev->bredr_state.connected || dev->le_state.connected)
		connected = TRUE;
	else
		connected = FALSE;

	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &connected);

	return TRUE;
}

static gboolean io_accept_event(GIOChannel *chan, GIOCondition cond, gpointer data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	GIOChannel *io;
	int nsk;

	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
		return FALSE;

	if (data == &l2cap_sock) {
		struct sockaddr_l2 addr;
		socklen_t len = sizeof(addr);

		nsk = accept(l2cap_sock, (struct sockaddr *) &addr, &len);
	} else if (data == &unix_sock) {
		struct sockaddr_un addr;
		socklen_t len = sizeof(addr);

		nsk = accept(unix_sock, (struct sockaddr *) &addr, &len);
	} else
		return FALSE;

	if (nsk < 0) {
		error("Can't accept connection: %s", strerror(errno));
		return TRUE;
	}

	io = g_io_channel_unix_new(nsk);
	g_io_channel_set_close_on_unref(io, TRUE);

	g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
					io_session_event, data);

	g_io_channel_unref(io);

	return TRUE;
}

static gboolean io_session_event(GIOChannel *chan, GIOCondition cond, gpointer data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	sdp_pdu_hdr_t hdr;
	uint8_t *buf;
	int sk, len, size;

	if (cond & G_IO_NVAL)
		return FALSE;

	sk = g_io_channel_unix_get_fd(chan);

	if (cond & (G_IO_HUP | G_IO_ERR)) {
		sdp_svcdb_collect_all(sk);
		return FALSE;
	}

	len = recv(sk, &hdr, sizeof(sdp_pdu_hdr_t), MSG_PEEK);
	if (len < 0 || (unsigned int) len < sizeof(sdp_pdu_hdr_t)) {
		sdp_svcdb_collect_all(sk);
		return FALSE;
	}

	size = sizeof(sdp_pdu_hdr_t) + ntohs(hdr.plen);
	buf = malloc(size);
	if (!buf)
		return TRUE;

	len = recv(sk, buf, size, 0);
	/* Check here only that the received message is not empty.
	 * Incorrect length of message should be processed later
	 * inside handle_request() in order to produce ErrorResponse.
	 */
	if (len <= 0) {
		sdp_svcdb_collect_all(sk);
		free(buf);
		return FALSE;
	}

	handle_request(sk, buf, len);
	void handle_request(int sk, uint8_t *data, int len)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct sockaddr_l2 sa;
		socklen_t size;
		sdp_req_t req;

		size = sizeof(sa);
		if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0) {
			error("getpeername: %s", strerror(errno));
			return;
		}

		if (sa.l2_family == AF_BLUETOOTH) {
			struct l2cap_options lo;

			memset(&lo, 0, sizeof(lo));
			size = sizeof(lo);

			if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &lo, &size) < 0) {
				error("getsockopt: %s", strerror(errno));
				return;
			}

			bacpy(&req.bdaddr, &sa.l2_bdaddr);
			req.mtu = lo.omtu;
			req.local = 0;
			memset(&sa, 0, sizeof(sa));
			size = sizeof(sa);

			if (getsockname(sk, (struct sockaddr *) &sa, &size) < 0) {
				error("getsockname: %s", strerror(errno));
				return;
			}

			bacpy(&req.device, &sa.l2_bdaddr);
		} else {
			bacpy(&req.device, BDADDR_ANY);
			bacpy(&req.bdaddr, BDADDR_LOCAL);
			req.mtu = 2048;
			req.local = 1;
		}

		req.sock = sk;
		req.buf  = data;
		req.len  = len;

		process_request(&req);
		static void process_request(sdp_req_t *req)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *)req->buf;
			sdp_pdu_hdr_t *rsphdr;
			sdp_buf_t rsp;
			uint8_t *buf = malloc(USHRT_MAX);
			int status = SDP_INVALID_SYNTAX;

			memset(buf, 0, USHRT_MAX);
			rsp.data = buf + sizeof(sdp_pdu_hdr_t);
			rsp.data_size = 0;
			rsp.buf_size = USHRT_MAX - sizeof(sdp_pdu_hdr_t);
			rsphdr = (sdp_pdu_hdr_t *)buf;

			if (ntohs(reqhdr->plen) != req->len - sizeof(sdp_pdu_hdr_t)) {
				status = SDP_INVALID_PDU_SIZE;
				goto send_rsp;
			}
			switch (reqhdr->pdu_id) {
			case SDP_SVC_SEARCH_REQ:
				SDPDBG("Got a svc srch req");
				status = service_search_req(req, &rsp);
				rsphdr->pdu_id = SDP_SVC_SEARCH_RSP;
				break;
			case SDP_SVC_ATTR_REQ:
				SDPDBG("Got a svc attr req");
				status = service_attr_req(req, &rsp);
				rsphdr->pdu_id = SDP_SVC_ATTR_RSP;
				break;
			case SDP_SVC_SEARCH_ATTR_REQ:
				SDPDBG("Got a svc srch attr req");
				status = service_search_attr_req(req, &rsp);
				rsphdr->pdu_id = SDP_SVC_SEARCH_ATTR_RSP;
				break;
			/* Following requests are allowed only for local connections */
			case SDP_SVC_REGISTER_REQ:
				SDPDBG("Service register request");
				if (req->local) {
					status = service_register_req(req, &rsp);
					rsphdr->pdu_id = SDP_SVC_REGISTER_RSP;
				}
				break;
			case SDP_SVC_UPDATE_REQ:
				SDPDBG("Service update request");
				if (req->local) {
					status = service_update_req(req, &rsp);
					rsphdr->pdu_id = SDP_SVC_UPDATE_RSP;
				}
				break;
			case SDP_SVC_REMOVE_REQ:
				SDPDBG("Service removal request");
				if (req->local) {
					status = service_remove_req(req, &rsp);
					rsphdr->pdu_id = SDP_SVC_REMOVE_RSP;
				}
				break;
			default:
				error("Unknown PDU ID : 0x%x received", reqhdr->pdu_id);
				status = SDP_INVALID_SYNTAX;
				break;
			}
			static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				int status = 0, plen, totscanned;
				uint8_t *pdata, *pResponse = NULL;
				unsigned int max;
				int scanned, rsp_count = 0;
				sdp_list_t *pattern = NULL, *seq = NULL, *svcList;
				sdp_cont_state_t *cstate = NULL;
				short cstate_size = 0;
				uint8_t dtd = 0;
				sdp_buf_t tmpbuf;
				size_t data_left;

				tmpbuf.data = NULL;
				pdata = req->buf + sizeof(sdp_pdu_hdr_t);
				data_left = req->len - sizeof(sdp_pdu_hdr_t);
				scanned = extract_des(pdata, data_left, &pattern, &dtd, SDP_TYPE_UUID);
				if (scanned == -1) {
					status = SDP_INVALID_SYNTAX;
					goto done;
				}
				totscanned = scanned;

				SDPDBG("Bytes scanned: %d", scanned);

				pdata += scanned;
				data_left -= scanned;

				if (data_left < sizeof(uint16_t)) {
					status = SDP_INVALID_SYNTAX;
					goto done;
				}

				max = get_be16(pdata);

				pdata += sizeof(uint16_t);
				data_left -= sizeof(uint16_t);

				SDPDBG("Max Attr expected: %d", max);

				if (data_left < sizeof(sdp_pdu_hdr_t)) {
					status = SDP_INVALID_SYNTAX;
					goto done;
				}

				/* extract the attribute list */
				scanned = extract_des(pdata, data_left, &seq, &dtd, SDP_TYPE_ATTRID);
				if (scanned == -1) {
					status = SDP_INVALID_SYNTAX;
					goto done;
				}

				pdata += scanned;
				data_left -= scanned;

				totscanned += scanned + sizeof(uint16_t) + 1;

				plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
				if (plen < totscanned || plen != totscanned + *(uint8_t *)pdata) {
					status = SDP_INVALID_PDU_SIZE;
					goto done;
				}

				/*
				 * if continuation state exists attempt
				 * to get rsp remainder from cache, else send error
				 */
				if (sdp_cstate_get(pdata, data_left, &cstate) < 0) {
					status = SDP_INVALID_SYNTAX;
					goto done;
				}

				svcList = sdp_get_record_list();

				tmpbuf.data = malloc(USHRT_MAX);
				tmpbuf.data_size = 0;
				tmpbuf.buf_size = USHRT_MAX;
				memset(tmpbuf.data, 0, USHRT_MAX);

				/*
				 * Calculate Attribute size according to MTU
				 * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))
				 */
				max = MIN(max, req->mtu - sizeof(sdp_pdu_hdr_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));

				/* pull header for AttributeList byte count */
				buf->data += sizeof(uint16_t);
				buf->buf_size -= sizeof(uint16_t);

				if (cstate == NULL) {
					/* no continuation state -> create new response */
					sdp_list_t *p;
					for (p = svcList; p; p = p->next) {
						sdp_record_t *rec = p->data;
						if (sdp_match_uuid(pattern, rec->pattern) > 0 &&
								sdp_check_access(rec->handle, &req->device)) {
							rsp_count++;
							status = extract_attrs(rec, seq, &tmpbuf);

							SDPDBG("Response count : %d", rsp_count);
							SDPDBG("Local PDU size : %d", tmpbuf.data_size);
							if (status) {
								SDPDBG("Extract attr from record returns err");
								break;
							}
							if (buf->data_size + tmpbuf.data_size < buf->buf_size) {
								/* to be sure no relocations */
								sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);
								tmpbuf.data_size = 0;
								memset(tmpbuf.data, 0, USHRT_MAX);
							} else {
								error("Relocation needed");
								break;
							}
							SDPDBG("Net PDU size : %d", buf->data_size);
						}
					}
					if (buf->data_size > max) {
						sdp_cont_state_t newState;

						memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
						newState.timestamp = sdp_cstate_alloc_buf(buf);
						/*
						 * Reset the buffer size to the maximum expected and
						 * set the sdp_cont_state_t
						 */
						buf->data_size = max;
						newState.cStateValue.maxBytesSent = max;
						cstate_size = sdp_set_cstate_pdu(buf, &newState);
					} else
						cstate_size = sdp_set_cstate_pdu(buf, NULL);
				} else {
					/* continuation State exists -> get from cache */
					sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
					if (pCache && cstate->cStateValue.maxBytesSent < pCache->data_size) {
						uint16_t sent = MIN(max, pCache->data_size - cstate->cStateValue.maxBytesSent);
						pResponse = pCache->data;
						memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent);
						buf->data_size += sent;
						cstate->cStateValue.maxBytesSent += sent;
						if (cstate->cStateValue.maxBytesSent == pCache->data_size)
							cstate_size = sdp_set_cstate_pdu(buf, NULL);
						else
							cstate_size = sdp_set_cstate_pdu(buf, cstate);
					} else {
						status = SDP_INVALID_CSTATE;
						SDPDBG("Non-null continuation state, but null cache buffer");
					}
				}

				if (!rsp_count && !cstate) {
					/* found nothing */
					buf->data_size = 0;
					sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);
					sdp_set_cstate_pdu(buf, NULL);
				}

				/* push header */
				buf->data -= sizeof(uint16_t);
				buf->buf_size += sizeof(uint16_t);

				if (!status) {
					/* set attribute list byte count */
					put_be16(buf->data_size - cstate_size, buf->data);
					buf->data_size += sizeof(uint16_t);
				}

			done:
				free(cstate);
				free(tmpbuf.data);
				if (pattern)
					sdp_list_free(pattern, free);
				if (seq)
					sdp_list_free(seq, free);
				return status;
			}

		send_rsp:
			if (status) {
				rsphdr->pdu_id = SDP_ERROR_RSP;
				put_be16(status, rsp.data);
				rsp.data_size = sizeof(uint16_t);
			}

			SDPDBG("Sending rsp. status %d", status);

			rsphdr->tid  = reqhdr->tid;
			rsphdr->plen = htons(rsp.data_size);

			/* point back to the real buffer start and set the real rsp length */
			rsp.data_size += sizeof(sdp_pdu_hdr_t);
			rsp.data = buf;

			/* stream the rsp PDU */
			if (send(req->sock, rsp.data, rsp.data_size, 0) < 0)
				error("send: %s (%d)", strerror(errno), errno);

			SDPDBG("Bytes Sent : %d", rsp.data_size);

			free(rsp.data);
			free(req->buf);
		}
	}

	return TRUE;
}

static void ag_confirm(GIOChannel *chan, gpointer data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	const char *server_uuid, *remote_uuid;
	struct headset *hs;
	gboolean hfp_active;
	bdaddr_t src, dst;
	int perr;
	GError *err = NULL;
	uint8_t ch;

	DBG(" ");
	bt_io_get(chan, &err,
				BT_IO_OPT_SOURCE_BDADDR, &src,
				BT_IO_OPT_DEST_BDADDR, &dst,
				BT_IO_OPT_CHANNEL, &ch,
				BT_IO_OPT_INVALID);

    if (err) {
		error("%s", err->message);
		g_error_free(err);
		goto drop;
	}

	if (ch == DEFAULT_HS_AG_CHANNEL) {
		hfp_active = FALSE;
		server_uuid = HSP_AG_UUID;
		remote_uuid = HSP_HS_UUID;
	} else {
		hfp_active = TRUE;
		server_uuid = HFP_AG_UUID;
		remote_uuid = HFP_HS_UUID;
	}

	hs = headset_get_device(&src, &dst, TRUE);

	if (!hs) {
        DBG("not hs\n");
		goto drop;
    }

	if (!manager_allow_headset_connection(hs)) {
		DBG("Refusing headset: too many existing connections");
		goto drop;
	}
	// david puzzle
	//if (!device->headset)
	if(!hs->had_inited)
	{
		btd_device_add_uuid(hs->btd_dev, remote_uuid);
		//if (!device->headset)
		if (!hs->had_inited) {
            DBG("hs not inited\n");
			goto drop;
        }
	}

	if (headset_get_state(hs) > HEADSET_STATE_DISCONNECTED) {
		DBG("Refusing new connection since one already exists");
		goto drop;
	}

	set_hfp_active(hs, hfp_active);
	void set_hfp_active(struct headset *hs, gboolean active)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		hs->hfp_active = active;
	}
	if (headset_connect_rfcomm(hs, chan) < 0) {
		error("headset_connect_rfcomm failed");
		DBG("headset_connect_rfcomm failed");
		goto drop;
	}
	int headset_connect_rfcomm(struct headset *hs, GIOChannel *io)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);

		if (hs->tmp_rfcomm)
			return -EALREADY;

		hs->tmp_rfcomm = g_io_channel_ref(io);

		return 0;
	}

	headset_set_state(hs, HEADSET_STATE_CONNECTING);
    DBG("call headset device request authorization");
	perr = headset_device_request_authorization(hs, server_uuid,headset_auth_cb, hs);
	int headset_device_request_authorization(struct headset *hs,
						const char *uuid, service_auth_cb cb,
						void *user_data)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct dev_priv *priv = hs->priv;
		struct service_auth *auth;
		int err;

		DBG("");
		auth = g_try_new0(struct service_auth, 1);
		if (!auth)
			return -ENOMEM;

		auth->cb = cb;
		auth->user_data = user_data;

		priv->auths = g_slist_append(priv->auths, auth);
		if (g_slist_length(priv->auths) > 1)
			return 0;

		if (priv->authorized || headset_device_is_connected(hs)) {
			priv->auth_idle_id = g_idle_add(auth_idle_cb, hs);
			return 0;
		}

		auth->id = btd_request_authorization(&hs->src, &hs->dst, uuid, auth_cb,hs);
		if (auth->id < 0) {
			priv->auths = g_slist_remove(priv->auths, auth);
			g_free(auth);
		}
		guint btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
							const char *uuid, service_auth_cb cb,
							void *user_data)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			struct btd_adapter *adapter;
			GSList *l;

			DBG("");
			if (bacmp(src, BDADDR_ANY) != 0) { //
				adapter = adapter_find(src);
				if (!adapter)
					return 0;

				return adapter_authorize(adapter, dst, uuid, cb, user_data);
			}

			for (l = adapters; l != NULL; l = g_slist_next(l)) {
				guint id;

				adapter = l->data;

				id = adapter_authorize(adapter, dst, uuid, cb, user_data);
				if (id != 0)
					return id;
			}
			static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
								const char *uuid, service_auth_cb cb,
								void *user_data)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct service_auth *auth;
				struct btd_device *device;
				static guint id = 0;

				device = btd_adapter_find_device(adapter, dst, BDADDR_BREDR);
				if (!device)
					return 0;

				if (device_is_disconnecting(device)) {
					DBG("Authorization request while disconnecting");
					return 0;
				}

				/* Device connected? */
				if (!g_slist_find(adapter->connections, device))
					btd_error(adapter->dev_id,
						"Authorization request for non-connected device!?");

				auth = g_try_new0(struct service_auth, 1);
				if (!auth)
					return 0;

				auth->cb = cb;
				auth->user_data = user_data;
				auth->uuid = uuid;
				auth->device = device;
				auth->adapter = adapter;
				auth->id = ++id;
				auth->svc_id = device_wait_for_svc_complete(device, svc_complete, auth);
				unsigned int device_wait_for_svc_complete(struct btd_device *dev,
											device_svc_cb_t func,
											void *user_data)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					/* This API is only used for BR/EDR (for now) */
					struct bearer_state *state = &dev->bredr_state;
					static unsigned int id = 0;
					struct svc_callback *cb;

					cb = g_new0(struct svc_callback, 1);
					cb->func = func;
					cb->user_data = user_data;
					cb->dev = dev;
					cb->id = ++id;

					dev->svc_callbacks = g_slist_prepend(dev->svc_callbacks, cb);

					if (state->svc_resolved || !main_opts.reverse_sdp)
						cb->idle_id = g_idle_add(svc_idle_cb, cb);
					else if (dev->discov_timer > 0) {
						g_source_remove(dev->discov_timer);
						dev->discov_timer = g_idle_add(start_discovery, dev);
					}

					return cb->id;
				}

				g_queue_push_tail(adapter->auths, auth);

				return auth->id;
			}

			return 0;
		}

		return auth->id;
	}
    DBG("perr: %d", perr);
	if (perr < 0) {
		DBG("Authorization denied: %s", strerror(-perr));
		headset_set_state(hs, HEADSET_STATE_DISCONNECTED);
		return;
	}

	hs->hs_preauth_id = g_io_add_watch(chan,
					G_IO_NVAL | G_IO_HUP | G_IO_ERR,
					hs_preauth_cb, hs);

	hs->auto_connect = auto_connect;

	return;

drop:
    DBG("shutdown channel\n");
	g_io_channel_shutdown(chan, TRUE, NULL);
}

static gboolean svc_idle_cb(gpointer user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct svc_callback *cb = user_data;
	struct btd_device *dev = cb->dev;

	dev->svc_callbacks = g_slist_remove(dev->svc_callbacks, cb);

	cb->func(cb->dev, 0, cb->user_data);
	static void svc_complete(struct btd_device *dev, int err, void *user_data)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct service_auth *auth = user_data;
		struct btd_adapter *adapter = auth->adapter;

		auth->svc_id = 0;

		if (adapter->auth_idle_id != 0)
			return;

		adapter->auth_idle_id = g_idle_add(process_auth_queue, adapter);
		static gboolean process_auth_queue(gpointer user_data)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			struct btd_adapter *adapter = user_data;
			DBusError err;

			DBG("");
			adapter->auth_idle_id = 0;

			dbus_error_init(&err);
			dbus_set_error_const(&err, ERROR_INTERFACE ".Rejected", NULL);

			while (!g_queue_is_empty(adapter->auths)) {
				struct service_auth *auth = adapter->auths->head->data;
				struct btd_device *device = auth->device;
				const char *dev_path;

				/* Wait services to be resolved before asking authorization */
				if (auth->svc_id > 0)
					return FALSE;

				if (device_is_trusted(device) == TRUE) {
					auth->cb(NULL, auth->user_data);
					goto next;
				}
				gboolean device_is_trusted(struct btd_device *device)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					return device->trusted;
				}

				/* If agent is set authorization is already ongoing */
				if (auth->agent)
					return FALSE;

				auth->agent = agent_get(NULL);
				if (auth->agent == NULL) { //
					DBG("Authentication attempt without agent, auto accept");
					//auth->cb(&err, auth->user_data);
					auth->cb(NULL, auth->user_data);
					// headset.c
					static void auth_cb(DBusError *derr, void *user_data)
					{
						printf("jokerb %s:in %d.\n",__func__,__LINE__);
						struct headset *hs = user_data;
						struct dev_priv *priv = hs->priv;

						if (derr == NULL)
							priv->authorized = TRUE;

						while (priv->auths) {
							struct service_auth *auth = priv->auths->data;

							auth->cb(derr, auth->user_data);
							priv->auths = g_slist_remove(priv->auths, auth);
							g_free(auth);
							static void headset_auth_cb(DBusError *derr, void *user_data)
							{
								printf("jokerb %s:in %d.\n",__func__,__LINE__);
								struct headset *hs = user_data;
								GError *err = NULL;
								GIOChannel *io;

								DBG("");
								if (hs->hs_preauth_id) {
									g_source_remove(hs->hs_preauth_id);
									hs->hs_preauth_id = 0;
								}

								if (derr && dbus_error_is_set(derr)) {
									error("Access denied: %s", derr->message);
									headset_set_state(hs, HEADSET_STATE_DISCONNECTED);
									return;
								}

								io = headset_get_rfcomm(hs);
								GIOChannel *headset_get_rfcomm(struct headset *hs)
								{
									printf("jokerb %s:in %d.\n",__func__,__LINE__);
									return hs->tmp_rfcomm;
								}

								if (!bt_io_accept(io, headset_connect_cb, hs, NULL, &err)) {
									error("bt_io_accept: %s", err->message);
									g_error_free(err);
									headset_set_state(hs, HEADSET_STATE_DISCONNECTED);
									return;
								}
							}
						}
					}
					goto next;
				}
				struct agent *agent_get(const char *owner)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct agent *agent;

					if (owner) {
						agent = g_hash_table_lookup(agent_list, owner);
						if (agent)
							return agent_ref(agent);
					}

					if (!queue_isempty(default_agents))
						return agent_ref(queue_peek_head(default_agents));

					return NULL;
				}

				dev_path = device_get_path(device);

				if (agent_authorize_service(auth->agent, dev_path, auth->uuid,
							agent_auth_cb, adapter, NULL) < 0) {
					auth->cb(&err, auth->user_data);
					goto next;
				}

				break;

		next:
				if (auth->agent)
					agent_unref(auth->agent);

				g_free(auth);

				g_queue_pop_head(adapter->auths);
			}

			dbus_error_free(&err);

			return FALSE;
		}
	}

	g_free(cb);

	return FALSE;
}

static gboolean accept_cb(GIOChannel *io, GIOCondition cond,
							gpointer user_data)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct accept *accept = user_data;
	GError *gerr = NULL;

	/* If the user aborted this accept attempt */
	if ((cond & G_IO_NVAL) || check_nval(io))
		return FALSE;

	if (cond & (G_IO_HUP | G_IO_ERR)) {
		int err, sk_err, sock = g_io_channel_unix_get_fd(io);
		socklen_t len = sizeof(sk_err);

		if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
			err = -errno;
		else
			err = -sk_err;

		if (err < 0)
			ERROR_FAILED(&gerr, "HUP or ERR on socket", -err);
	}

	accept->connect(io, gerr, accept->user_data);
	static void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct headset *hs = user_data;
		struct pending_connect *p = hs->pending;
		char hs_address[18];

		DBG("");
		if (err) {
			error("%s", err->message);
			goto failed;
		}

		/* For HFP telephony isn't ready just disconnect */
		if (hs->hfp_active && !ag.telephony_ready) {
			error("Unable to accept HFP connection since the telephony "
					"subsystem isn't initialized");
			goto failed;
		}

		hs->rfcomm = hs->tmp_rfcomm;
		hs->tmp_rfcomm = NULL;

		ba2str(&hs->dst, hs_address);

		if (p)
			p->io = NULL;
		else
			hs->auto_dc = FALSE;

		g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,
				(GIOFunc) rfcomm_io_cb, hs);

		DBG("%s: Connected to %s", hs->path, hs_address);

		hs->slc = g_new0(struct headset_slc, 1);
		hs->slc->sp_gain = 15;
		hs->slc->mic_gain = 15;
		hs->slc->nrec = TRUE;

		/* In HFP mode wait for Service Level Connection */
		if (hs->hfp_active) {
			DBG("return\n");
			return;
		}

		headset_set_state(hs, HEADSET_STATE_CONNECTED);

		if (p && p->target_state == HEADSET_STATE_PLAYING) {
			DBG("call sco connect\n");
			p->err = sco_connect(hs, NULL, NULL, NULL);
			if (p->err < 0)
				goto failed;
			return;
		}

		if (p && p->msg) {
			DBusMessage *reply = dbus_message_new_method_return(p->msg);
			g_dbus_send_message(hs->conn, reply);
		}

		pending_connect_finalize(hs);

		DBG("return\n");
		return;

	failed:
		if (p && p->msg)
			error_connect_failed(hs->conn, p->msg, p->err);
		pending_connect_finalize(hs);
		if (hs->rfcomm) {
			DBG("set hs connected\n");
			headset_set_state(hs, HEADSET_STATE_CONNECTED);
		}
		else {
			DBG("set hs disconnected\n");
			headset_set_state(hs, HEADSET_STATE_DISCONNECTED);
		}
		DBG("return\n");
	}

	g_clear_error(&gerr);

	return FALSE;
}


############## hfp init ###########
static int hfp_init(void)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
	if (connection == NULL)
		return -EIO;
	config = load_config_file(CONFIGDIR "/audio.conf");

	if(config)
	{
		gboolean b;
		GError *err = NULL;
		b = g_key_file_get_boolean(config, "General", "AutoConnect", &err);
		if (err) {
			DBG("audio.conf: %s", err->message);
			g_clear_error(&err);
		} else
			auto_connect = b;

		err = NULL;
		int i;
		i = g_key_file_get_integer(config, "Headset", "MaxConnected",
						&err);
		if (err) {
			DBG("audio.conf: %s", err->message);
			g_clear_error(&err);
		} else
			max_connected_headsets = i;
	}

	static struct btd_adapter_driver headset_server_driver = {
		.name	= "audio-headset",
		.probe	= headset_server_probe,
		.remove	= headset_server_remove,
	};

	btd_register_adapter_driver(&headset_server_driver);
	int btd_register_adapter_driver(struct btd_adapter_driver *driver)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		adapter_drivers = g_slist_append(adapter_drivers, driver);

		if (driver->probe == NULL)
			return 0;

		adapter_foreach(probe_driver, driver);
		void adapter_foreach(adapter_cb func, gpointer user_data)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			g_slist_foreach(adapters, (GFunc) func, user_data);
			static void probe_driver(struct btd_adapter *adapter, gpointer user_data)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				struct btd_adapter_driver *driver = user_data;
				int err;

				if (driver->probe == NULL)
					return;

				err = driver->probe(adapter);
				if (err < 0) {
					btd_error(adapter->dev_id, "%s: %s (%d)", driver->name,
										strerror(-err), -err);
					return;
				}

				adapter->drivers = g_slist_prepend(adapter->drivers, driver);
			}
		}
		

		return 0;
	}
	DBG("dnf register  hfp profile\n");
	btd_profile_register(&hfp_profile);
	int btd_profile_register(struct btd_profile *profile)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		profiles = g_slist_append(profiles, profile);
		return 0;
	}

	return 0;

failed:
	btd_unregister_adapter_driver(&headset_server_driver);
	btd_profile_unregister(&hfp_profile);
	if (connection) {
		dbus_connection_unref(connection);
		connection = NULL;
	}
	return -EIO;
}

static int hfp_device_probe(struct btd_service *service)
{
	printf("jokerb %s:in %d.\n",__func__,__LINE__);
	struct btd_device *dev = btd_service_get_device(service);
	struct btd_adapter *adapter = device_get_adapter(dev);

	DBG("path %s", device_get_path(dev));

	struct headset *hs;

	hs = headset_get_device( btd_adapter_get_address(adapter), device_get_address(dev),TRUE); <tag98>
	if (!hs){
		DBG("unable to get a headset object");
		return -1;	//	david error ???
	}
	struct headset *headset_get_device(const bdaddr_t *src,
						const bdaddr_t *dst,
						gboolean create)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		struct headset *hs;
		struct btd_adapter *adapter;
		struct btd_device *device;
		char addr[18];
		const char *path;

		hs = headset_find_device(src, dst);
		if (hs)
			return hs;

		if (!create)
			return NULL;

		ba2str(src, addr);

		adapter = adapter_find(src);
		if (!adapter) {
			error("Unable to get a btd_adapter object for %s",
					addr);
			return NULL;
		}

		device = btd_adapter_get_device(adapter, dst, BDADDR_BREDR);
		if (!device) {
			error("Unable to get btd_device object for %s", addr);
			return NULL;
		}

		path = device_get_path(device);
		const char *device_get_path(const struct btd_device *device)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			if (!device)
				return NULL;

			return device->path;
		}

		hs = headset_device_register(connection, device, path, src, dst);
		if (!hs)
			return NULL;
		struct headset *headset_device_register(DBusConnection *conn,
							struct btd_device *dev,
							const char *path,
							const bdaddr_t *src,
							const bdaddr_t *dst)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			struct headset *hs;
			const sdp_record_t *record;

			if (!conn || !path)
				return NULL;
			DBG("%d\n", __LINE__);
			hs = g_new0(struct headset, 1);
			hs->btd_dev = btd_device_ref(dev);
			hs->path = g_strdup(path);
			bacpy(&hs->dst, dst);
			bacpy(&hs->src, src);
			hs->conn = dbus_connection_ref(conn);
			hs->priv = g_new0(struct dev_priv, 1);
			//headset->priv->state = AUDIO_STATE_DISCONNECTED;
			hs->priv->hs_state =HEADSET_STATE_DISCONNECTED;
			hs->rfcomm_ch = -1;
			hs->search_hfp = 1;

			if (headset_callback_id == 0) {
				headset_callback_id = headset_add_state_cb(device_headset_cb,NULL);
				static unsigned int headset_add_state_cb(headset_state_cb cb, void *user_data)
				{
					printf("jokerb %s:in %d.\n",__func__,__LINE__);
					struct headset_state_callback *state_cb;
					static unsigned int id = 0;

					state_cb = g_new(struct headset_state_callback, 1);
					state_cb->cb = cb;
					state_cb->user_data = user_data;
					state_cb->id = ++id;

					headset_callbacks = g_slist_append(headset_callbacks, state_cb);

					return state_cb->id;
				}
			}

			return hs;
		}

		headsets = g_slist_append(headsets, hs);

		return hs;
	}
	handle_hfp_uuid(service, hs);
	static void handle_hfp_uuid(struct btd_service *service, struct headset *hs)
	{
		printf("jokerb %s:in %d.\n",__func__,__LINE__);
		if(hs->had_inited) {
			headset_update(service, hs);
		} else {
			hs = headset_init(service, hs);
			struct headset *headset_init(struct btd_service *service, struct headset *hs)
			{
				printf("jokerb %s:in %d.\n",__func__,__LINE__);
				/* get record : handle uuid */
				uuid_t uuid;
				struct btd_profile *p= btd_service_get_profile(service);
				const char *uuidstr  = p->remote_uuid;

				if (bt_string2uuid(&uuid, uuidstr) < 0) {
					error("%s not detected as an UUID-128", uuidstr);
					return NULL;
				}

				if (!sdp_uuid128_to_uuid(&uuid) && uuid.type != SDP_UUID16) {
					error("Could not convert %s to a UUID-16", uuidstr);
					return NULL;
				}
				uint16_t svc = uuid.value.uuid16;

				const sdp_record_t *record;
				record = btd_device_get_record(hs->btd_dev, uuidstr);
				if (!record)
					goto register_iface;

				switch (svc)
				{
					case HANDSFREE_SVCLASS_ID:
							hs->hfp_handle = record->handle;
							break;
					case HEADSET_SVCLASS_ID:
							hs->hsp_handle = record->handle;
							break;
					default:
						DBG("Invalid record passed to headset_init");
						g_free(hs);
						return NULL;
				}

			register_iface:
				#define AUDIO_HEADSET_INTERFACE "org.bluez.Headset"
				if (!g_dbus_register_interface(hs->conn, hs->path,
								AUDIO_HEADSET_INTERFACE,
								headset_methods, headset_signals, NULL,
								hs, path_unregister)) {
					g_free(hs);
					return NULL;
				}

				DBG("Registered interface %s on path %s",AUDIO_HEADSET_INTERFACE, hs->path);

				hs->had_inited = 1;
				return hs;
			}
		}

	}
	if(hs) {
		btd_service_set_user_data(service, hs);
		void btd_service_set_user_data(struct btd_service *service, void *user_data)
		{
			printf("jokerb %s:in %d.\n",__func__,__LINE__);
			btd_assert(service->state == BTD_SERVICE_STATE_UNAVAILABLE);
			service->user_data = user_data;
		}
	}

	hs->service = btd_service_ref(service);
	DBG("leave %s\n",__FUNCTION__);
	return 0;
}
